
定义: handler是一个模块
作用:
调用时机:
使用方法:
phase handler:
此类型的模块也被直接称为handler模块。主要负责处理客户端请求并产生待响应内容,比如ngx_http_static_module模块,负责客户端的静态页面请求处理并将对应的磁盘文件准备为响应内容输出。
Handler 模块(callback):接受来自客户端的请求并构建响应头和响应体。
基本上作为第三方开发者最可能开发的就是三种类型的模块,即handler,filter和load-balancer。Handler模块就是接收来自客户端的请求并产生输出的模块。
配置文件中使用location指令可以配置content handler模块,当Nginx系统启动的时候,每个handler模块都有一次机会把自己关联到对应的location上。
handler模块处理的结果通常有三种情况: 处理成功,处理失败(处理的时候发生了错误)或者是拒绝去处理。在拒绝处理的情况下,这个location的处理就会由默认的handler模块来进行处理。例如,当请求一个静态文件的时候,如果关联到这个location上的一个handler模块拒绝处理,就会由默认的ngx_http_static_module模块进行处理,该模块是一个典型的handler模块。
2 添加handler模块
1.location 一致
2.ngx_module_t module名字要一致
root@iZbp12g0t474mdbecfyuk4Z:~/nginx-1.16.1# ls nginx_test_mp_module
config nginx_test_memory_module.c
config文件(配置文件名必须是config):
ngx_addon_name=nginx_test_mp_module
HTTP_MODULES="$HTTP_MODULES nginx_test_mp_module"
NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/nginx_test_memory_module.c"
1 添加handler模块
1.1.location 一致
1.2.ngx_module_t module名字要一致
root@iZbp12g0t474mdbecfyuk4Z:~/nginx-1.16.1# ls nginx_test_mp_module
config nginx_test_memory_module.c
config文件(配置文件名必须是config):
ngx_addon_name=nginx_test_mp_module
HTTP_MODULES="$HTTP_MODULES nginx_test_mp_module"
NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/nginx_test_memory_module.c"
在前面已经看到了这个hello handler module的部分重要的结构。
该模块提供了2个配置指令,仅可以出现在location指令的作用域中。
- 对于flag类型的配置指令,当值为off的时候,使用ngx_conf_set_flag_slot函数,会转化为0,为on,则转化为非0。
- 另外一个是,我提供了merge_loc_conf函数,但是却没有设置到模块的上下文定义中。
这样有一个缺点,就是如果一个指令没有出现在配置文件中的时候,配置信息中的值,将永远会保持在create_loc_conf中的初始化的值。
2 下面来完整的给出ngx_http_hello_module模块的完整代码。
#include#include #include typedef struct { ngx_str_t hello_string; ngx_int_t hello_counter; }ngx_http_hello_loc_conf_t; static ngx_int_t ngx_http_hello_init(ngx_conf_t *cf); static void *ngx_http_hello_create_loc_conf(ngx_conf_t *cf); static char *ngx_http_hello_string(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static char *ngx_http_hello_counter(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static ngx_command_t ngx_http_hello_commands[] = { { ngx_string("hello_string"), NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS|NGX_CONF_TAKE1, ngx_http_hello_string, NGX_HTTP_LOC_CONF_OFFSET, offsetof(ngx_http_hello_loc_conf_t, hello_string), NULL }, { ngx_string("hello_counter"), NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, ngx_http_hello_counter, NGX_HTTP_LOC_CONF_OFFSET, offsetof(ngx_http_hello_loc_conf_t, hello_counter), NULL }, ngx_null_command }; static int ngx_hello_visited_times = 0; static ngx_http_module_t ngx_http_hello_module_ctx = { NULL, ngx_http_hello_init, NULL, NULL, NULL, NULL, ngx_http_hello_create_loc_conf, NULL }; ngx_module_t ngx_http_hello_module = { NGX_MODULE_V1, &ngx_http_hello_module_ctx, ngx_http_hello_commands, NGX_HTTP_MODULE, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NGX_MODULE_V1_PADDING }; static ngx_int_t ngx_http_hello_handler(ngx_http_request_t *r) { ngx_int_t rc; ngx_buf_t *b; ngx_chain_t out; ngx_http_hello_loc_conf_t* my_conf; u_char ngx_hello_string[1024] = {0}; ngx_uint_t content_length = 0; ngx_log_error(NGX_LOG_EMERG, r->connection->log, 0, "ngx_http_hello_handler is called!"); my_conf = ngx_http_get_module_loc_conf(r, ngx_http_hello_module); if (my_conf->hello_counter == NGX_CONF_UNSET || my_conf->hello_counter == 0) { ngx_sprintf(ngx_hello_string, "%s", my_conf->hello_string.data); } else { ngx_sprintf(ngx_hello_string, "%s Visited Times:%d", my_conf->hello_string.data, ++ngx_hello_visited_times); } ngx_log_error(NGX_LOG_EMERG, r->connection->log, 0, "hello_string:%s", ngx_hello_string); content_length = ngx_strlen(ngx_hello_string); rc = ngx_http_discard_request_body(r); ngx_str_set(&r->headers_out.content_type, "text/html"); if (r->method == NGX_HTTP_HEAD) { r->headers_out.status = NGX_HTTP_OK; r->headers_out.content_length_n = content_length; return ngx_http_send_header(r); } b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t)); out.buf = b; out.next = NULL; b->pos = ngx_hello_string; b->last = ngx_hello_string + content_length; b->memory = 1; b->last_buf = 1; r->headers_out.status = NGX_HTTP_OK; r->headers_out.content_length_n = content_length; rc = ngx_http_send_header(r); return ngx_http_output_filter(r, &out); } static void *ngx_http_hello_create_loc_conf(ngx_conf_t *cf) { ngx_http_hello_loc_conf_t* local_conf = NULL; local_conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_hello_loc_conf_t)); ngx_str_null(&local_conf->hello_string); local_conf->hello_counter = NGX_CONF_UNSET; return local_conf; } static char * ngx_http_hello_string(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_http_hello_loc_conf_t* local_conf; local_conf = conf; char* rv = ngx_conf_set_str_slot(cf, cmd, conf); ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "hello_string:%s", local_conf->hello_string.data); return rv; } static char *ngx_http_hello_counter(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_http_hello_loc_conf_t* local_conf; local_conf = conf; char* rv = NULL; rv = ngx_conf_set_flag_slot(cf, cmd, conf); ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "hello_counter:%d", local_conf->hello_counter); return rv; } static ngx_int_t ngx_http_hello_init(ngx_conf_t *cf) { ngx_http_handler_pt *h; ngx_http_core_main_conf_t *cmcf; cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); h = ngx_array_push(&cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers); *h = ngx_http_hello_handler; return NGX_OK; }
notes: 模块定义,模块上下文定义(ctx),模块配置结构(commands),Handler处理函数.
实现一个handler的步骤:
- 编写模块基本结构。包括模块的定义,模块上下文结构,模块的配置结构等。
- 如果有loc_conf,需要定义自己loc_conf结构,以及conf结构创建,赋值函数。
- 实现handler的挂载函数。根据模块的需求选择正确的挂载方式。
- 编写handler处理函数。模块的功能主要通过这个函数来完成。
注意:这里并没有提供merge_loc_conf函数,因为我们这个模块的配置指令已经确定只出现在NGX_HTTP_LOC_CONF中这一个层次上,不会发生需要合并的情况。
1:模块定义结构
ngx_module_t ngx_http_hello_module
定义一个ngx_module_t类型的变量来说明这个模块本身的信息.
它告诉了nginx这个模块的一些信息,上面定义的配置信息,还有模块上下文信息,都是通过这个结构来告诉nginx系统的,也就是加载模块的上层代码,都需要通过定义的这个结构,来获取这些信息。
这个模块中最主要要定义的就是CTX上下文结构与commands配置结构数组。
2:上下文结构
ngx_http_module_t ngx_http_hello_module_ctx;
这是一个ngx_http_module_t类型的静态变量。这个变量实际上是提供一组回调函数指针,这些函数有在创建存储配置信息的对象的函数,也有在创建前和创建后会调用的函数。这些函数都将被nginx在合适的时间进行调用。
这个例子中,该结构最重要的是
调用了一个handler挂载函数ngx_http_hello_init
调用了一个loc_conf创建函数ngx_http_hello_create_loc_conf
3:模块的配置结构
ngx_command_t ngx_http_hello_commands[];
在我的理解里,这个数组实现的功能是将我们在nginx.conf文件中定义的配置读取并存储进loc_conf结构中,conf结构已经在上下文结构中被创建。
4:loc_conf与其创建赋值函数
本例子中,定义了一个结构体:
1 typedef struct
2 {
3 ngx_str_t hello_string;
4 ngx_int_t hello_counter;
5 }ngx_http_hello_loc_conf_t;
该结构体储存了本模块的配置变量。(option)
通过上下文结构中的调用的ngx_http_hello_create_loc_conf函数创建,通过配置结构中的ngx_http_hello_string以及ngx_http_hello_counter函数赋值。
5:handler 挂载函数
ngx_int_t ngx_http_hello_init;
该函数在上下文结构中被调用,决定了handler函数具体在11个PHASE中的哪个PHASE被调用。关于PHASE定义以及函数具体实现参看网站以及hello模块源码。
参考:nginx handler模块_nuptxiaoli-CSDN博客
Nginx_handler模块发开(hello模块结构解析) - PaulWeiHan - 博客园
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)