Nginx教程:实现一个简单的http模块(2)

二、定义mytest模块的初始化时的回调方法,这个结构主要用来在解析配置文件时使用,在每一个main、srv、loc块中用它的回调方法,产生自己配置结构的地址,供http框架使用,保存各个块的配置项,这里我们并没有需要解析的配置项,所以我们简单的把所有方法置NULL。定义如下:

//mytest模块上下文,都为NULL即是说在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_modules数组中,这样在Nginx初始化时会调用模块的所有初始化方法,(上面的ngx_http_module_t类型的ngx_http_mytest_module_ctx)

ngx_module_t ngx_http_mytest_module = {   
    NGX_MODULE_V1, //由Nginx定义的宏来初始化前七个成员 
    &ngx_http_mytest_module_ctx,  //模块的上下文结构体,指向特定模块的公共方法 
    ngx_http_mytest_commands,  //处理配置项的结构体数组 
    NGX_HTTP_MODULE,  //模块类型 
  //Nginx在启动停止过程中七个执行点的函数指针 
    NULL,   
    NULL,   
    NULL,   
    NULL,   
    NULL,   
    NULL,   
    NULL,   
 
    NGX_MODULE_V1_PADDING  //由Nginx定义的宏定义剩下的8个保留字段 
}; 

四、处理用户请求

通过上面的结构定义,当在location块中出现mytest配置项时,ngx_http_mytest函数会被调用,这时会将ngx_http_core_loc_conf_t结构的handler成员指针指向自己处理请求函数,http框架在接收完所有头部后就会调用handler指向的方法,handler原型如下:

typedef ngx_int_t (*ngx_http_handler_pt)(ngx_http_request_t *r);

ngx_http_request_t类型包含了所有本次请求的所有头和包体,以及一个与之相关联的一个内存池对象,用于请求响应的内存分配,我想这也是Nginx能够很好提高内存使用的一个成功之处。

//配置项对应的回调函数,当配置项中出现mytest配置项时将调用这个函数   
static char *  ngx_http_mytest(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)   
{    //ckcf并不是指特定的location块内的数据结构,他可以是mian、srv、loc级别的配置项 
//每个http{},sever{},location{}都有一个ngx_http_core_loc_conf_t类型的数据结构 
        ngx_http_core_loc_conf_t *clcf;   
     
//找到mytest配置项所在的配置块 
    clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);   
     
//http框架在处理用户请求进行到NGX_HTTP_CONTENT_PHASE阶段是,如果请求的主机名,URI与配置项所在的配置块相匹配时,就调用 
//clcf中的handle方法处理这个请求 
        //NGX_HTTP_CONTENT_PHASE用于处理http请求内容的阶段,这是大部分http模块通常介入的阶段 
clcf->handler = ngx_http_mytest_handler;   
   
    return NGX_CONF_OK;   
}   

我们的处理请求函数只是简单的丢弃请求,并发送自己构造的响应。定义的用户请求的处理函数如下:

//实际完成处理的回调函数   
static ngx_int_t ngx_http_mytest_handler(ngx_http_request_t *r)   
{   
/请求方法 
    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;   
    }   
  //构造响应头部 
    ngx_str_t type = ngx_string("text/plain");   
    ngx_str_t response = ngx_string("hello world ! \n\rthis is my first Nginx module test ! ");   
    r->headers_out.status = NGX_HTTP_OK;   
    r->headers_out.content_length_n = response.len;   
    r->headers_out.content_type = type;   
  //发送http头部,其中也包括响应行 
    rc = ngx_http_send_header(r);   
    if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {   
        return rc;   
    }   
   
  ngx_buf_t *b;   
  //根据请求中传来的内存池对象,创建内存buf 
  b = ngx_create_temp_buf(r->pool, response.len);   
    if (b == NULL) {   
        return NGX_HTTP_INTERNAL_SERVER_ERROR;   
    }   
  //有效内容从pos位置开始,复制respon的内容 
    ngx_memcpy(b->pos, response.data, response.len);   
    //有效内容到last结束 
    b->last = b->pos + response.len;   
    //因为ngx_buf_t可以由ngx_chain_t链表链起来,last_buf可以标记这是最后一块待处理的缓冲区,简化处理 
    b->last_buf = 1;   
 //将内存buf用链表链起来,作为ngx_http_output_filter的跌入个参数 
    ngx_chain_t out;   
    out.buf = b;   
  //标记这是最后一个ngx_chain_t 
    out.next = NULL;   
   
    return ngx_http_output_filter(r, &out);   
}   

到此所有的模块都定义结束了,下面就是如何把自己的模块编译到Nginx中

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/6bad7427ea4977783275d8c8296ff39e.html