Nginx将第三方模块编译到nginx中的方法:将源代码文件和config放在一个目录中,然后执行configure --add-module=PATH (以上文件的地址) ,就可以在执行正常编译安装流程时完成nginx编译工作;

通过编写配置mytest模块,可以在http{},server{},location{}块中声明配置mytest,如

location /mytest/ {

    mytest;

}

那么当用户请求的URI中匹配到/mytest/ ,就会调用我们自定义的ngx_mytest_handle方法来处理这个用户请求;

1、编写config文件

ngx_addon_name=ngx_http_mytest_module

HTTP_MODULES="$HTTP_MODULES ngx_http_mytest_module"

NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_mytest_module.c"

 

  • ngx_addon_name:仅在configure执行时使用,一般设置为模块

 

  • HTTP_MODULES:保存所有的HTTP模块名称,每个HTTP模块间由空格符相连。在重新设置HTTP_MODULES变量时,不要直接覆盖它,因为configure调用到自定义的config脚本前,已经将各个HTTP模块设置到HTTP_MODULES变量中了,因此,要像如下这样设

"$HTTP_MODULES ngx_http_mytest_module"

 

  • NGX_ADDON_SRCS:用于指定新增模块的源代码,多个待编译的源代码间以空格符相连。注意,在设置NGX_ADDON_SRCS时可以使用$ngx_addon_dir变量,它等价于configure执行时--add-module=PATH的PATH参数。

 

 

2、编写ngx_http_mytest_module.c

#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_http.h>

//mytest配置项处理


static ngx_int_t ngx_http_mytest_handle(ngx_http_request_t *r){
        //必须是GET或者HEAD方法,否则返回405 Not Allowed
        if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))){
                return NGX_HTTP_NOT_ALLOWED;
        }

        //丢弃请求中的包体
        ngx_int_t rc = ngx_http_discard_request_body(r);
        if(rc!=NGX_OK){
                return rc;
        }

        //设置返回的Content-Type
        ngx_str_t type = ngx_string("text/html;application/json;charset=utf-8");

        //返回的包体的内容
        ngx_str_t response = ngx_string("Hello World!");

        //设置返回的状态码
        r->headers_out.status = NGX_HTTP_OK;

        //响应包体是有包体内容的,需要设置Contetn-Length长度
        r->headers_out.content_length_n = response.len;

        //设置contetn-type
        r->headers_out.content_type = type;

        //发送自定义头部
        ngx_table_elt_t* h = ngx_list_push(&r->headers_out.headers);
        if(h == NULL){
                return NGX_ERROR;
        }

        h->hash = 1;
        h->key.len = sizeof("TestHead")-1;
        h->key.data = (u_char *) "TestHead";
        h->value.len = sizeof("TestValue") - 1;
        h->value.data = (u_char *) "TestValue";

        //发送HTTP头部
        rc = ngx_http_send_header(r);
        if (rc == NGX_ERROR || rc > NGX_OK || r->header_only){
                return rc;
        }

        //构建ngx_buf_t结构体准备发送包体
        ngx_buf_t *b;
        b = ngx_create_temp_buf(r->pool,response.len);
        if (b == NULL){
                return NGX_HTTP_INTERNAL_SERVER_ERROR;
        }

        //将responser复制到ngx_buf_t指向的内存中
        ngx_memcpy(b->pos,response.data,response.len);
        //注意,一定要设置好last指针
        b->last = b->pos + response.len;
        //声明这是最后一块缓存区
        b->last_buf = 1;

        //构造发送时的ngx_chain_t结构体
        ngx_chain_t out;
        //赋值ngx_buf_t
        out.buf = b;
        //设置next为null
        out.next = NULL;

        //最后一步为发送包体,发送结束后http框架会调用ngx_http_finalize_request方法结束请求
        return ngx_http_output_filter(r,&out);
}


static char *
ngx_http_mytest(ngx_conf_t *cf,ngx_command_t *cmd,void *conf){
        //首先找到mytest配置项所属的配置块;
        ngx_http_core_loc_conf_t *clcf;
        clcf = ngx_http_conf_get_module_loc_conf(cf,ngx_http_core_module);

        //如果请求的主机域名、URI、与mytest配置项所在的配置块相匹配,会调用我们实现的ngx_http_mytest_handle
        clcf->handler = ngx_http_mytest_handle;
        return NGX_CONF_OK;
}

static ngx_command_t ngx_http_mytest_commands[] = {

        {
          ngx_string("mytest"), //配置项名称

          //配置项类型,指定配置项可以出现的位置
          NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LMT_CONF|NGX_CONF_NOARGS,

          //处理配置项的参数,当配置块中出现mytest配置项时,Nginx会调用ngx_http_mytest方法 
          ngx_http_mytest,

          //在配置文件中的偏移量
          NGX_HTTP_LOC_CONF_OFFSET,
          0,
          NULL
        },

        ngx_null_command
};



//第三方模块可以介入HTTP框架7个阶段处理请求,如果有什么需要在http框架初始化完成的,就可以在这里设置
static ngx_http_module_t ngx_http_mytest_module_ctx = {
        NULL,   /* preconfiguration */
        NULL,   /* postconfiguration */
        NULL,   /* create main configuration */
        NULL,   /* init main configuration */
        NULL,   /* create server configuration */
        NULL,   /* merge server configuration */
        NULL,   /* create location configuration */
        NULL,   /* merge location configuration */
};

//定义mytest模块
ngx_module_t ngx_http_mytest_module = {
        NGX_MODULE_V1,
        &ngx_http_mytest_module_ctx,    /* module context  */
        ngx_http_mytest_commands,       /* modele 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
};

 

3、编译该模块

#运行configure文件,使用--add-module=PATH(config和ngx_module_http_mytest_module所在的问文件夹)

./configure --add-module=/usr/local/nginx-1.14.2/nginx-module/mytest-module

make

nginx -s stop

cp objs/nginx ../../nginx/sbin

#启动nginx
nginx