Nginx请求处理采用11阶段固定顺序的状态机模型,每阶段按序执行注册的handler,仅content阶段可生成响应体且支持默认兜底;其他阶段handler返回NGX_DECLINED继续遍历,NGX_OK进入下一阶段,错误则终止并记日志。

理解 Nginx 源码中 ngx_http_phases 的阶段化处理逻辑,关键在于抓住“请求生命周期被划分为固定阶段、每个阶段按序执行匹配的 handler、且仅一个 handler 可真正处理请求”这一核心机制。它不是简单的函数调用链,而是一套由框架严格控制的、带短路语义的状态机式调度系统。
阶段(phase)是请求处理的逻辑里程碑
Nginx 将 HTTP 请求生命周期切分为 11 个预定义阶段(如 NGX_HTTP_POST_READ_PHASE、NGX_HTTP_SERVER_REWRITE_PHASE、NGX_HTTP_CONTENT_PHASE 等),每个阶段代表一类职责明确的操作时机:
- 读取并初步解析请求(post-read):刚收到数据,做早期校验或强制跳转
- 重写类操作(server/content rewrite):修改 URI、host 或内部重定向
- 权限与访问控制(access、auth):鉴权、限流、黑白名单
- 实际内容生成(content):静态文件服务、反向代理、Lua 处理等
- 日志与清理(log):记录 access log,释放资源
这些阶段顺序固定、不可跳过、不可重排,构成一条单向推进的主干路径。
handler 绑定到阶段,但只在“归属阶段”被调度
模块通过 ngx_http_core_main_conf_t->phases[phase].handlers 将自己的 handler 注册到特定阶段。注意:
- 注册时指定的是
NGX_HTTP_XXX_PHASE常量,不是函数指针直接插入全局链表 - 所有 handler 按注册顺序存入该阶段的动态数组(
ngx_array_t),后续遍历执行 - 一个 handler 只会在其注册的阶段被考虑;不会跨阶段调用,也不会在非归属阶段“意外触发”
阶段内 handler 执行遵循“成功即退出,失败则继续”原则
进入某阶段后,Nginx 会顺序遍历该阶段所有 handler:
- 若 handler 返回 NGX_OK:表示“我已正常完成本阶段任务”,继续进入下一阶段
- 若返回 NGX_DECLINED:表示“我不处理,请下一个 handler 试试”,继续遍历同阶段剩余 handler
- 若返回 NGX_AGAIN 或 NGX_DONE:暂停当前请求,等待事件(如 upstream 响应),不进入下一阶段
- 若返回 NGX_ERROR、NGX_HTTP_XXX(如 403/500):立即终止流程,跳转至
NGX_HTTP_LOG_PHASE记录日志,并返回响应
特别注意:只有 content 阶段的 handler 被允许“真正产生响应体”;其他阶段 handler 若擅自调用 ngx_http_send_header() 或 ngx_http_output_filter(),会导致未定义行为。
content 阶段是特殊分支点,支持“无 handler 则回退到默认处理”
不同于其他阶段必须有至少一个 handler(否则报错),content 阶段允许为空。此时 Nginx 会自动启用“默认 content handler”:
- 若配置了
index、autoindex或try_files,走对应逻辑 - 若匹配到静态文件,交由
ngx_http_static_handler - 若未匹配任何 location,返回 404
这也是为什么你没显式配置 proxy_pass 或 echo,Nginx 仍能返回文件——底层有兜底策略。
掌握这个模型后,看 ngx_http_core_run_phases() 和 ngx_http_phase_handler_t 结构体就不再抽象:它本质是一个阶段索引 + 当前 handler 下标 + 请求状态的三元组驱动器,每次回调都决定“停、走、跳、错”。不复杂但容易忽略细节。

















