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).
void
ngx_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;
}
}
}