nginx处理请求流程
nginx启动时master进程加载配置文件,根据配置文件初始化监听的socket,fork worker进程。 worker进程与client建立socket连接处理请求,接收请求读取请求行、请求头、请求体。 处理请求,根据处理结果响应请求,响应行/头/体。
对应函数处理流程如下:
ngx_http_add_listening ---> ngx_http_init_connection ---> ngx_http_wait_request_handler ---> ngx_http_process_request_line ---> ngx_http_process_request_headers ---> ngx_http_process_request ---> ngx_http_handler ---> ngx_http_core_run_phases
nginx大部分event采用epoll EPOLLET边沿触发的方法来触发事件,只有listen端口的读事件是EPOLLLT水平触发。对于边沿触发,如果出现了可读事件,必须及时处理,否则可能会出现读事件不再触发,连接饿死的情况。
由此可见worker进程在处理完request_line和request_headers之后。 会进入ngx_http_core_module.c文件的phase入口函数:ngx_http_core_run_phases() 这就进入了著名的nginx处理请求十一个函数阶段。
十一个阶段,每个阶段有各自的checker和handler 通过cheker函数来判断是继续在本阶段handler,还是去下一个phase的handler处理。 或者跳到某个阶段handler处理。
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_TRY_FILES_PHASE,
? ? NGX_HTTP_CONTENT_PHASE,
?
? ? NGX_HTTP_LOG_PHASE
} ngx_http_phases;
ngx_http_core_run_phases执行十一阶段handler
遍历各个阶段的checker和handler 如果返回结果为NGX_AGAIN交由下一个phase处理,OK则返回。
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为指向 ngx_http_phase_handler_t 结构的指针,存储了各phase的checker和handler。
? ? ph = cmcf->phase_engine.handlers;
? ? // while顺序执行checker
? ? // 根据checker指引,handler处理根据处理结果进行下一步走向
? ? while (ph[r->phase_handler].checker) {
? ? ? ? rc = ph[r->phase_handler].checker(r, &ph[r->phase_handler]);
? ? ? ? if (rc == NGX_OK) {
? ? ? ? ? ? return;
? ? ? ? }
? ? }
}
十一阶段的handler是如何添加的
各个phase的handler 添加到ngx_http_core_module的cmcf->phase_engine.handlers数组中。 使用 ngx_http_phase_t 结构存储每个阶段可用的处理函数(handler),它实际上是动态数组 ngx_array_t,元素类型为 ngx_http_handler_pt,存储在ngx_http_core_main_conf_t中。 所以cmcf结构为ngx_http_core_main_conf_t。
参考文章:nginx phase handler处理及log phase处理_晓镁的博客-CSDN博客
ngx_http_block() 函数会调用所有模块的 postconfiguration 函数把自己的 handler 处理函数添加到 phases 数组里。
随后 nginx 执行函数 ngx_http_init_phase_handlers(),该函数会遍历 phases 数组,计算 handler 模块的数量,统计所以已经注册的 handler 数量并分配内存,再安阶段分类,把每个 handler 与对应阶段的 checker 组合起来,填入引擎数组。
for (m = 0; ngx_modules[m]; m++) {
? ? ? ? ...
? ? ? ? if (module->postconfiguration) {
? ? ? ? ? ? if (module->postconfiguration(cf) != NGX_OK) {
? ? ? ? ? ? ? ? return NGX_CONF_ERROR;
? ? ? ? ? ? }
? ? ? ? }
? ? }
? ? ...
? ? if (ngx_http_init_phase_handlers(cf, cmcf) != NGX_OK) {
? ? ? ? return NGX_CONF_ERROR;
? ? }
编译nginx模块的handler
例如编译nginx时 enable ngx_http_geoip_module
找到对应的模块代码文件,找到ngx_module_t ngx_http_geoip_module ?
ngx_module_t ?ngx_http_geoip_module = {
? ? NGX_MODULE_V1,
? ? &ngx_http_geoip_module_ctx, ? ? ? ? ? ?/* module context */
? ? ngx_http_geoip_commands, ? ? ? ? ? ? ? /* module directives */
? ? NGX_HTTP_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
};
通过module context 找到 ngx_http_geoip_module_ctx 又找到 preconfiguration 为 ngx_http_geoip_add_variables,ngx_http_geoip_add_variables就是handler函数。
static ngx_http_module_t ?ngx_http_geoip_module_ctx = {
? ? ngx_http_geoip_add_variables, ? ? ? ? ?/* preconfiguration */
? ? NULL, ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?/* postconfiguration */
? ? ngx_http_geoip_create_conf, ? ? ? ? ? ?/* create main configuration */
? ? ngx_http_geoip_init_conf, ? ? ? ? ? ? ?/* init main configuration */
? ? NULL, ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?/* create server configuration */
? ? NULL, ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?/* merge server configuration */
? ? NULL, ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?/* create location configuration */
? ? NULL ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /* merge location configuration */
};
模块编译部分后面再详细说明。 ?
|