• nginx自定义模块记录上游服务器特定响应头


    功能,服务器通过扩展自定义命令,记录上游的服务器返回的特定响应头内容,记录到本地文件中

    代码如下:

    /*
     * Copyright (C) Ciaos
     */
    
    #include <ngx_config.h>
    #include <ngx_core.h>
    #include <ngx_http.h>
    
    typedef struct {
        ngx_str_t    header;
        ngx_str_t    savefile;
    } ngx_http_tiaowuban_filter_conf_t;
    
    static void *ngx_http_tiaowuban_filter_create_conf(ngx_conf_t *cf);
    static char *ngx_http_tiaowuban_filter_merge_conf(ngx_conf_t *cf, void *parent,void *child);
    
    static ngx_int_t ngx_http_tiaowuban_filter_init(ngx_conf_t *cf);
    
    static ngx_command_t  ngx_http_tiaowuban_filter_commands[] = {
        { ngx_string("tiaowuban_header"),
            NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
            ngx_conf_set_str_slot,
            NGX_HTTP_LOC_CONF_OFFSET,
            offsetof(ngx_http_tiaowuban_filter_conf_t, header),
            NULL },
        { ngx_string("tiaowuban_savefile"),
            NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
            ngx_conf_set_str_slot,
            NGX_HTTP_LOC_CONF_OFFSET,
            offsetof(ngx_http_tiaowuban_filter_conf_t, savefile),
            NULL },
    
        ngx_null_command
    };
    
    static ngx_http_module_t  ngx_http_tiaowuban_filter_module_ctx = {
        NULL,                                  /* preconfiguration */
        ngx_http_tiaowuban_filter_init,              /* postconfiguration */
    
        NULL,                                  /* create main configuration */
        NULL,                                  /* init main configuration */
    
        NULL,                                  /* create server configuration */
        NULL,                                  /* merge server configuration */
    
        ngx_http_tiaowuban_filter_create_conf,       /* create location configration */
        ngx_http_tiaowuban_filter_merge_conf         /* merge location configration */
    };
    
    
    ngx_module_t  ngx_http_tiaowuban_filter_module = {
        NGX_MODULE_V1,
        &ngx_http_tiaowuban_filter_module_ctx,       /* module context */
        ngx_http_tiaowuban_filter_commands,          /* module directives */
        NGX_HTTP_MODULE,                       /* module type */
        NULL,                                  /* init master */
        NULL,                                  /* init module */
        NULL,                                  /* init process */
        NULL,                                  /* init thread */
        NULL,                                  /* exit thread */
        NULL,                                  /* exit process */
        NULL,                                  /* exit master */
        NGX_MODULE_V1_PADDING
    };
    
    static ngx_http_output_header_filter_pt  ngx_http_next_header_filter;
    static ngx_http_output_body_filter_pt    ngx_http_next_body_filter;
    
    static ngx_int_t 
    ngx_http_tiaowuban_filter_header_filter(ngx_http_request_t *r)
    {
        ngx_uint_t        buffsize = 1024, n;
        ngx_table_elt_t        *ho;
        ngx_buf_t        out_buff;
        u_char            buff[buffsize];
        ngx_file_t        file;
        ngx_list_t        *headers;
        ngx_http_tiaowuban_filter_conf_t *clcf;
        
        clcf = ngx_http_get_module_loc_conf(r, ngx_http_tiaowuban_filter_module);
        if(clcf == NULL) {
            return NGX_ERROR;
        }
    
        if(clcf->header.len != 0){
            headers = &r->headers_out.headers;
            for (n = 0; n < headers->part.nelts; n++) {
                ho = &((ngx_table_elt_t *)headers->part.elts)[n];
                if (ngx_strncmp(ho->key.data, clcf->header.data, clcf->header.len) == 0) {
                    if (clcf->savefile.data == NULL){
                        return NGX_ERROR;
                    }
                    file.fd = ngx_open_file(clcf->savefile.data, NGX_FILE_APPEND, NGX_FILE_CREATE_OR_OPEN, 0600);
                    if (file.fd == NGX_INVALID_FILE) {
                        return NGX_ERROR;
                    }
                    file.log = r->connection->log;
                
                    out_buff.pos = out_buff.last = buff;
                    out_buff.last = ngx_http_time(out_buff.last, time(0));
                    out_buff.last = ngx_snprintf(out_buff.last, r->connection->addr_text.len+1, "|%s", r->connection->addr_text.data);
                    buffsize -= out_buff.last - out_buff.pos;
                    out_buff.last = ngx_snprintf(out_buff.last, buffsize, "|%s
    ", (u_char *) ho->value.data);
    
                    (void) ngx_write_file(&file, out_buff.pos, out_buff.last - out_buff.pos, 0);
    
                    if (ngx_close_file(file.fd) == NGX_FILE_ERROR) {
                         ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno, ngx_close_file_n " "%s" failed", clcf->savefile.data);
                    }
                }
            }
        }
    
        return ngx_http_next_header_filter(r);
    }
    
    static ngx_int_t 
    ngx_http_tiaowuban_filter_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
    {
        return ngx_http_next_body_filter(r, in);
    }
    
    static void *
    ngx_http_tiaowuban_filter_create_conf(ngx_conf_t *cf)
    {
        ngx_http_tiaowuban_filter_conf_t  *clcf;
    
        clcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_tiaowuban_filter_conf_t));
        if (clcf == NULL) {
            return NULL;
        }
    
        return clcf;
    }
    
    
    static char *
    ngx_http_tiaowuban_filter_merge_conf(ngx_conf_t *cf, void *parent, void *child)
    {
        ngx_http_tiaowuban_filter_conf_t *prev = parent;
        ngx_http_tiaowuban_filter_conf_t *clcf = child;
    
        ngx_conf_merge_str_value(clcf->header, prev->header, "");
        ngx_conf_merge_str_value(clcf->savefile, prev->savefile, "");
    
        return NGX_CONF_OK;
    }
    
    static ngx_int_t
    ngx_http_tiaowuban_filter_init(ngx_conf_t *cf)
    {
        ngx_http_next_header_filter = ngx_http_top_header_filter;
        ngx_http_top_header_filter = ngx_http_tiaowuban_filter_header_filter;
    
        ngx_http_next_body_filter = ngx_http_top_body_filter;
        ngx_http_top_body_filter = ngx_http_tiaowuban_filter_body_filter;
    
        return NGX_OK;
    }

    测试用例如下

    use Test::Nginx::Socket;
    repeat_each(1);
    plan tests => 3 * repeat_each() * blocks() - 1;
    
    our $config = <<"_EOC_";
            location /test {
                    tiaowuban_header "tiaowubanCtrl";
                    tiaowuban_savefile /usr/local/nginx/logs/tiaowuban.bill;
                    proxy_pass      http://127.0.0.1/;
            }
    _EOC_
    
    run_tests();
    
    __DATA__
    
    === TEST 1: upstream header one
    --- http_config eval
    "
        server{
            listen  80;
            location / {
                    add_header tiaowubanCtrl "testone";
                    return 200 "this is test one";
            }
        }
    "
    --- config eval: $::config
    --- request
    GET /test
    --- pre_remove_files eval
    ["/usr/local/nginx/logs/tiaowuban.bill"]
    --- error_code: 200
    --- response_headers
    tiaowubanCtrl: testone
    --- response_body_like: this is test one
    --- output_files_like
    /usr/local/nginx/logs/tiaowuban.bill: testone
    
    === TEST 2: upstream header two
    --- http_config eval
    "
        server{
            listen  80;
            location / {
                    add_header tiaowubanCtrl "testtwo";
                    return 200 "this is test two";
            }
        }
    "
    --- config eval: $::config
    --- request
    GET /test
    --- pre_remove_files eval
    ["/usr/local/nginx/logs/tiaowuban.bill"]
    --- error_code: 200
    --- response_headers
    tiaowubanCtrl: testtwo
    --- response_body_like: this is test two
    --- output_files_like
    /usr/local/nginx/logs/tiaowuban.bill: testtwo
    
    === TEST 3: upstream no header
    //--- ONLY
    --- http_config eval
    "
        server{
            listen  80;
            location / {
                    return 200 "this is test three";
            }
        }
    "
    --- config eval: $::config
    --- request
    GET /test
    --- pre_remove_files eval
    ["/usr/local/nginx/logs/tiaowuban.bill"]
    --- error_code: 200
    --- response_body_like: this is test three
    --- files_not_exist eval
    ["/usr/local/nginx/logs/tiaowuban.bill"]
    --- timeout: 10

    文件内容如下:

    Wed, 12 Nov 2014 08:29:30 GMT|10.0.2.2|hello tiaowuban
    Wed, 12 Nov 2014 08:30:20 GMT|10.0.2.2|hello tiaowuban
    Wed, 12 Nov 2014 08:30:24 GMT|10.0.2.2|hello tiaowuban
    Wed, 12 Nov 2014 08:30:43 GMT|10.0.2.2|hello tiaowuban
    Wed, 12 Nov 2014 08:30:46 GMT|10.0.2.2|hello tiaowuban
  • 相关阅读:
    Philosophy is systematic reflective thinking on life.
    HashMap与HashTable的区别、HashMap与HashSet的关系
    android Intent机制详解
    Android Parcelable理解与使用(对象序列化)
    Java并发编程:volatile关键字解析
    JavaEE 对象的串行化(Serialization)
    pytorch学习
    numpy的一些用法
    约瑟夫问题
    双向链表及其操作
  • 原文地址:https://www.cnblogs.com/ciaos/p/4092335.html
Copyright © 2020-2023  润新知