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;}
}
}