1. 引言Nginx 以其高性能、高并发和模块化架构闻名。对于开发者而言理解 Nginx 处理 HTTP 请求的完整生命周期——即11 个处理阶段Phases——是编写高效、正确模块的基石。本文将深入剖析这 11 个阶段结合 Nginx 源码并通过一个完整的实战示例带你从零开发一个可独立加载的 Nginx 模块助你真正掌握 Nginx 模块开发的精髓。2. Nginx 模块与阶段概览2.1 模块化架构Nginx 本身是一个轻量级的核心大部分功能如 HTTP 处理、反向代理、SSL 等都由模块提供。模块通过钩子Handlers和过滤器Filters介入请求处理流程。2.2 11 个处理阶段下面这张流程图直观地展示了这 11 个阶段的执行顺序、关键分支如重写后循环以及核心阶段的产出是否NGX_HTTP_POST_READ_PHASE读取请求头后NGX_HTTP_SERVER_REWRITE_PHASEServer 级别 URI 重写NGX_HTTP_FIND_CONFIG_PHASE查找 Location 配置NGX_HTTP_REWRITE_PHASELocation 级别 URI 重写NGX_HTTP_POST_REWRITE_PHASEURI 是否发生变化NGX_HTTP_PREACCESS_PHASE访问控制前限流/限速NGX_HTTP_ACCESS_PHASE访问控制IP黑白名单/认证NGX_HTTP_POST_ACCESS_PHASE访问控制后403处理NGX_HTTP_PRECONTENT_PHASE生成内容前try_files/autoindexNGX_HTTP_CONTENT_PHASE生成内容核心阶段产出HTTP 响应体NGX_HTTP_LOG_PHASE日志记录Nginx 将 HTTP 请求的处理过程划分为 11 个有序的阶段定义在src/http/ngx_http_core_module.h中typedefenum{NGX_HTTP_POST_READ_PHASE0,// 读取请求头后的阶段NGX_HTTP_SERVER_REWRITE_PHASE,// Server 级别 URI 重写NGX_HTTP_FIND_CONFIG_PHASE,// 查找 Location 配置NGX_HTTP_REWRITE_PHASE,// Location 级别 URI 重写NGX_HTTP_POST_REWRITE_PHASE,// URI 重写后的检查阶段NGX_HTTP_PREACCESS_PHASE,// 访问控制前阶段如限流NGX_HTTP_ACCESS_PHASE,// 访问控制阶段如 IP 黑白名单NGX_HTTP_POST_ACCESS_PHASE,// 访问控制后阶段NGX_HTTP_PRECONTENT_PHASE,// 生成内容前阶段NGX_HTTP_CONTENT_PHASE,// 生成内容阶段核心NGX_HTTP_LOG_PHASE// 日志记录阶段}ngx_http_phases;这些阶段按顺序执行每个阶段可以注册多个处理函数Handler它们会依次被调用直至某个函数返回NGX_OK或NGX_DECLINED。3. 各阶段源码级解析3.1NGX_HTTP_POST_READ_PHASE时机Nginx 读取完 HTTP 请求的头部Header之后但在进行任何其他处理之前。典型用途解析自定义请求头、记录原始请求信息。源码位置src/http/ngx_http_request.c中的ngx_http_process_request()函数。// 简化后的调用逻辑voidngx_http_process_request(ngx_http_request_t*r){// ... 读取并解析请求头 ...if(ngx_http_process_request_header(r)!NGX_OK){return;}// 执行 POST_READ 阶段的处理器ngx_http_handler(r,NGX_HTTP_POST_READ_PHASE);// ... 后续处理 ...}3.2NGX_HTTP_SERVER_REWRITE_PHASE时机在server块内根据server_name匹配到虚拟服务器后执行server块内的rewrite指令。典型用途基于域名或全局规则进行 URL 重写。源码位置src/http/ngx_http_rewrite_module.c。3.3NGX_HTTP_FIND_CONFIG_PHASE时机这是一个内部阶段用于根据请求的 URI 查找匹配的location块。典型用途开发者通常不在此阶段注册处理器Nginx 内部使用。源码位置src/http/ngx_http_core_module.c中的ngx_http_core_find_config_phase()。3.4NGX_HTTP_REWRITE_PHASE时机在匹配到具体的location块后执行该location块内的rewrite指令。典型用途对特定路径的请求进行 URL 重写。3.5NGX_HTTP_POST_REWRITE_PHASE时机REWRITE_PHASE执行完毕后。如果之前的重写导致 URI 发生变化Nginx 会在此阶段重新执行FIND_CONFIG_PHASE以匹配新的location。典型用途防止重写后的循环并进行最终检查。3.6NGX_HTTP_PREACCESS_PHASE时机在正式的访问控制阶段检查之前。典型用途实现连接数限制ngx_http_limit_conn_module、请求频率限制ngx_http_limit_req_module。源码位置src/http/modules/ngx_http_limit_conn_module.c。3.7NGX_HTTP_ACCESS_PHASE时机执行访问控制逻辑。典型用途IP 黑白名单ngx_http_access_module、用户认证ngx_http_auth_basic_module。源码位置src/http/modules/ngx_http_access_module.c。3.8NGX_HTTP_POST_ACCESS_PHASE时机ACCESS_PHASE执行完毕后。如果访问被拒绝此阶段会发送403 Forbidden响应。典型用途处理访问控制阶段后的收尾工作。3.9NGX_HTTP_PRECONTENT_PHASE时机在生成响应内容之前。典型用途处理try_files指令、生成静态文件索引ngx_http_autoindex_module、处理mirror请求。源码位置src/http/modules/ngx_http_try_files_module.c。3.10NGX_HTTP_CONTENT_PHASE时机核心阶段负责生成 HTTP 响应体。典型用途代理请求ngx_http_proxy_module、FastCGIngx_http_fastcgi_module、返回静态文件ngx_http_static_module。源码位置src/http/ngx_http_core_module.c中的ngx_http_core_content_phase()。// 核心内容处理逻辑ngx_int_tngx_http_core_content_phase(ngx_http_request_t*r,ngx_http_phase_handler_t*ph){// 查找并执行注册的 content handlerngx_http_handler_pt handlerr-content_handler;if(handler){returnhandler(r);}// 如果没有自定义 handler则尝试默认处理如静态文件returnNGX_DECLINED;}3.11NGX_HTTP_LOG_PHASE时机请求处理完毕准备记录日志时。典型用途自定义日志格式、记录请求处理耗时等。源码位置src/http/modules/ngx_http_log_module.c。4. 实战开发一个独立的 Nginx 模块我们将开发一个名为ngx_http_hello_phase_module的模块它会在REWRITE_PHASE和ACCESS_PHASE中插入自定义处理逻辑并通过独立的config文件加载。4.1 项目结构nginx-hello-phase-module/ ├── config └── ngx_http_hello_phase_module.c4.2 模块源码ngx_http_hello_phase_module.c#includengx_config.h#includengx_core.h#includengx_http.h// 模块上下文定义staticngx_int_tngx_http_hello_phase_handler(ngx_http_request_t*r);staticngx_int_tngx_http_hello_access_handler(ngx_http_request_t*r);staticchar*ngx_http_hello_phase(ngx_conf_t*cf,ngx_command_t*cmd,void*conf);// 指令定义staticngx_command_tngx_http_hello_phase_commands[]{{ngx_string(hello_phase),NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,ngx_http_hello_phase,NGX_HTTP_LOC_CONF_OFFSET,0,NULL},ngx_null_command};// 模块配置结构typedefstruct{ngx_flag_tenable;}ngx_http_hello_phase_loc_conf_t;// 创建 location 配置staticvoid*ngx_http_hello_phase_create_loc_conf(ngx_conf_t*cf){ngx_http_hello_phase_loc_conf_t*conf;confngx_pcalloc(cf-pool,sizeof(ngx_http_hello_phase_loc_conf_t));if(confNULL){returnNULL;}conf-enableNGX_CONF_UNSET;returnconf;}// 合并 location 配置staticchar*ngx_http_hello_phase_merge_loc_conf(ngx_conf_t*cf,void*parent,void*child){ngx_http_hello_phase_loc_conf_t*prevparent;ngx_http_hello_phase_loc_conf_t*confchild;ngx_conf_merge_value(conf-enable,prev-enable,0);returnNGX_CONF_OK;}// 指令处理函数解析 hello_phase 指令并注册处理器staticchar*ngx_http_hello_phase(ngx_conf_t*cf,ngx_command_t*cmd,void*conf){ngx_http_core_loc_conf_t*clcf;ngx_http_hello_phase_loc_conf_t*hlcfconf;// 解析指令值char*rvngx_conf_set_flag_slot(cf,cmd,conf);if(rv!NGX_CONF_OK){returnrv;}// 如果指令值为 on则注册处理器if(hlcf-enable){// 获取当前 location 的核心配置clcfngx_http_conf_get_module_loc_conf(cf,ngx_http_core_module);// 注册一个处理器到 REWRITE_PHASEngx_http_handler_pt*hngx_array_push(clcf-phases[NGX_HTTP_REWRITE_PHASE].handlers);if(hNULL){returnNGX_CONF_ERROR;}*hngx_http_hello_phase_handler;// 注册一个处理器到 ACCESS_PHASEhngx_array_push(clcf-phases[NGX_HTTP_ACCESS_PHASE].handlers);if(hNULL){returnNGX_CONF_ERROR;}*hngx_http_hello_access_handler;}returnNGX_CONF_OK;}// REWRITE_PHASE 处理器staticngx_int_tngx_http_hello_phase_handler(ngx_http_request_t*r){ngx_log_error(NGX_LOG_INFO,r-connection-log,0,hello_phase: entering REWRITE_PHASE for URI: %V,r-uri);// 这里可以添加自定义的重写逻辑// 返回 NGX_DECLINED 让后续处理器继续执行returnNGX_DECLINED;}// ACCESS_PHASE 处理器staticngx_int_tngx_http_hello_access_handler(ngx_http_request_t*r){ngx_log_error(NGX_LOG_INFO,r-connection-log,0,hello_phase: entering ACCESS_PHASE for URI: %V,r-uri);// 示例拒绝访问 /secret 路径if(ngx_strncmp(r-uri.data,/secret,7)0){returnNGX_HTTP_FORBIDDEN;}returnNGX_DECLINED;}// 模块上下文staticngx_http_module_tngx_http_hello_phase_module_ctx{NULL,// preconfigurationNULL,// postconfigurationNULL,// create main configurationNULL,// init main configurationNULL,// create server configurationNULL,// merge server configurationngx_http_hello_phase_create_loc_conf,// create location configurationngx_http_hello_phase_merge_loc_conf// merge location configuration};// 模块定义ngx_module_tngx_http_hello_phase_module{NGX_MODULE_V1,ngx_http_hello_phase_module_ctx,// module contextngx_http_hello_phase_commands,// module directivesNGX_HTTP_MODULE,// module typeNULL,// init masterNULL,// init moduleNULL,// init processNULL,// init threadNULL,// exit threadNULL,// exit processNULL,// exit masterNGX_MODULE_V1_PADDING};4.3 独立配置文件configngx_addon_namengx_http_hello_phase_module HTTP_MODULES$HTTP_MODULES ngx_http_hello_phase_module NGX_ADDON_SRCS$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_hello_phase_module.c4.4 编译与加载编译为动态模块推荐./configure --add-dynamic-module/path/to/nginx-hello-phase-modulemakemodulessudomakeinstall在nginx.conf中加载load_module modules/ngx_http_hello_phase_module.so; http { server { listen 80; server_name example.com; location / { hello_phase on; # ... 其他配置 ... } location /secret { hello_phase on; # 访问 /secret 会被我们的模块拒绝 } } }5. 总结通过本文我们深入了解了 Nginx HTTP 处理的 11 个阶段并结合源码分析了每个阶段的作用。实战部分我们开发了一个独立的 Nginx 模块演示了如何在REWRITE_PHASE和ACCESS_PHASE中注册自定义处理器并通过config文件实现独立加载。掌握这些知识你将能够编写出更强大、更贴合业务需求的 Nginx 模块充分释放 Nginx 的潜力。