handler模块
作为第三方开发者咱们最有可能开发的三种类型的模块别离是:handler、filter和load-balancer。配置文件应用location指令能够配置content handler模块,每个handler都有一次机会把本人关联到对应的location上。
模块根本构造
大家都晓得Nginx 的配置信息分成了几个作用域(scope,有时也称作上下文),这就是 main, server, 以及
location。同样的每个模块提供的配置指令也能够呈现在这几个作用域里。那对于这三个作
用域的配置信息,每个模块就须要定义三个不同的数据结构去进行存储。
typedef struct { int count; //count struct in_addr addr; //ip} ngx_pv_table;
模块配置指令
一个模块的配置指令是定义在一个动态数组中的。
struct ngx_command_s { ngx_str_t name; //名称 ngx_uint_t type; //类型例如是main配置还是location配置以及有无参数 char *(*set)(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); //回调函数,解析到该命令之后,执行该函数 ngx_uint_t conf;//是不是http module ngx_uint_t offset;//指定该配置项值的准确寄存地位,个别指定为某一个构造体变量的字段便宜。 void *post;};
模块上下文构造
这是一个 ngx_http_module_t 类型的动态变量。这个变量实际上是提供一组回调函数指针,这些函数有在创立存储配置信息的对象的函数,也有在创立前和创立后会调用的函数。这些函数都将被 nginx 在适合的工夫进行调用。
typedef struct { ngx_int_t (*preconfiguration)(ngx_conf_t *cf);//在创立和读取该模块的配置信息之前被调用 ngx_int_t (*postconfiguration)(ngx_conf_t *cf);//在创立和读取该模块的配置信息之后被调用 void *(*create_main_conf)(ngx_conf_t *cf);//调用该函数创立本模块位于 http block 的配置信息存储构造。该函数胜利的时候,返回创立的配置对象。失败的u话,返回 NULL char *(*init_main_conf)(ngx_conf_t *cf, void *conf);//调用该函数初始化本模块位于 http block 的配置信息存储构造。该函数胜利的时候,返回 NGX_CONF_OK。失败的话,返回 NGX_CONF_ERROR 或谬误字符串。 void *(*create_srv_conf)(ngx_conf_t *cf);//调用该函数创立本模块位于 http server block 的配置信息存储构造,每个 server block 会创立一个。该函数胜利的时候,返回创立的配置对象。失败的话,返回 NULL。 char *(*merge_srv_conf)(ngx_conf_t *cf, void *prev, void *conf);//因为有些配置指令既能够呈现在 http block,也能够呈现在 http server block 中。那么遇到这种状况,每个 server都会有本人存储构造来存储该 server 的配置,然而在这种状况下 http block 中的配置与 server block 中的配置信息发生冲突的时候,就须要调用此函数进行合并,该函数并非必须提供,当预计到相对不会产生须要合并的状况的时候,就无需提供。当然为了平安起见还是倡议提供。该函数执行胜利的时候,返回 NGX_CONF_OK。失败的话,返回 NGX_CONF_ERROR 或谬误字符串 void *(*create_loc_conf)(ngx_conf_t *cf);//调用该函数创立本模块位于 location block 的配置信息存储构造。每个在配置中指明的 location 创立一个。该函数执行胜利,返回创立的配置对象。失败的话,返回 NULL。 char *(*merge_loc_conf)(ngx_conf_t *cf, void *prev, void *conf);} ngx_http_module_t;
模块定义
对于开发一个模块来说,咱们都须要定义一个 ngx_module_t 类型的变量来阐明这个模块自身的信息,从某种意义上来说,这是这个模块最重要的一个信息,它通知了 nginx 这个模块的一些信息,下面定义的配置信息,还有模块上下文信息,都是通过这个构造来通知 nginx零碎的,也就是加载模块的下层代码,都须要通过定义的这个构造,来获取这些信息。咱们先来看下 ngx_module_t 的定义
struct ngx_module_s { ngx_uint_t ctx_index; ngx_uint_t index; char *name; ngx_uint_t spare0; ngx_uint_t spare1; ngx_uint_t version; const char *signature; void *ctx; ngx_command_t *commands; ngx_uint_t type; ngx_int_t (*init_master)(ngx_log_t *log); ngx_int_t (*init_module)(ngx_cycle_t *cycle); ngx_int_t (*init_process)(ngx_cycle_t *cycle); ngx_int_t (*init_thread)(ngx_cycle_t *cycle); void (*exit_thread)(ngx_cycle_t *cycle); void (*exit_process)(ngx_cycle_t *cycle); void (*exit_master)(ngx_cycle_t *cycle); uintptr_t spare_hook0; uintptr_t spare_hook1; uintptr_t spare_hook2; uintptr_t spare_hook3; uintptr_t spare_hook4; uintptr_t spare_hook5; uintptr_t spare_hook6; uintptr_t spare_hook7;};
个别咱们能够这么定义
ngx_module_t ngx_epoll_module = { NGX_MODULE_V1, &ngx_epoll_module_ctx, /* module context */ ngx_epoll_commands, /* module directives */ NGX_EVENT_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};
handler编写步骤
typedef ngx_int_t (*ngx_http_handler_pt)(ngx_http_request_t *r);
提供处理函数。
- 编写模块根本构造。包含模块的定义,模块上下文构造,模块的配置构造等。
- 实现 handler 的挂载函数。依据模块的需要抉择正确的挂载形式。
- 编写 handler 处理函数。模块的性能次要通过这个函数来实现。
http模块解决流程
nginx的http解决流程蕴含11个阶段,这11个阶段是精华
typedef enum { NGX_HTTP_POST_READ_PHASE = 0, NGX_HTTP_SERVER_REWRITE_PHASE, NGX_HTTP_FIND_CONFIG_PHASE, NGX_HTTP_REWRITE_PHASE, NGX_HTTP_POST_REWRITE_PHASE, NGX_HTTP_PREACCESS_PHASE, NGX_HTTP_ACCESS_PHASE, NGX_HTTP_POST_ACCESS_PHASE, NGX_HTTP_PRECONTENT_PHASE, NGX_HTTP_CONTENT_PHASE, NGX_HTTP_LOG_PHASE} ngx_http_phases;
这些阶段当中咱们最次要关注的是content阶段,每个阶段都有若干个handler函数。通过ngx_http_init_phase_handlers函数将这个handler函数填入引擎组。
for (j = cmcf->phases[i].handlers.nelts - 1; j >= 0; j--) { ph->checker = checker; ph->handler = h[j]; ph->next = n; ph++; }//将handler填入引擎组的外围代码,后面通过switch case来判断每个阶段
具体handler的执行在函数ngx_http_core_phases(ngx_http_request_t *r).
voidngx_http_core_run_phases(ngx_http_request_t *r){ ngx_int_t rc; ngx_http_phase_handler_t *ph; ngx_http_core_main_conf_t *cmcf; cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); ph = cmcf->phase_engine.handlers; while (ph[r->phase_handler].checker) { rc = ph[r->phase_handler].checker(r, &ph[r->phase_handler]); //r->phase_handler的变换在checker中执行,checker执行该阶段中的checker函数,checker函数中执行handler函数,checker自身用来判断是否满足执行handler函数的条件 if (rc == NGX_OK) { return; } }}