Nginx状态机是11个固定序号、单向不可逆的请求处理阶段;请求依次通过各阶段,仅当本阶段所有handler返回NGX_OK才进入下一阶段,任一阶段返回错误则终止并跳至LOG_PHASE。

理解 Nginx 状态机中的各阶段,关键在于把它看作一条不可逆、顺序推进的请求处理流水线:每个阶段代表一个职责明确的“处理关口”,请求必须逐关通过,不能跳过,也不能倒退。
阶段本质是单向事件流,不是并行任务
Nginx 不是靠配置顺序或 location 嵌套来决定执行逻辑,而是由 11 个固定序号的 phase 构成硬性流程。请求一旦进入某个阶段,就只在这个阶段内遍历所有注册的 handler;只有当前阶段所有 handler 都返回 NGX_OK(表示本阶段完成),才会自动进入下一阶段。任何阶段中 handler 返回 NGX_ERROR 或 HTTP 错误码(如 403),都会立刻终止主流程,跳转至 LOG_PHASE 记录日志并返回响应。
核心阶段的功能与典型用途
POST_READ_PHASE:请求头刚收完、URI 还未匹配前的最早干预点。主要用于修正客户端真实 IP(如 realip 模块读取 X-Forwarded-For)、早期协议校验。此阶段极少自定义 handler,多数情况被快速跳过。
SERVER_REWRITE_PHASE 和 REWRITE_PHASE:前者在 server 块级生效(如 server 内的 rewrite 指令),后者在匹配到 location 后生效(location 内的 rewrite)。两者都修改 URI 或触发内部重定向,但不生成响应。注意:rewrite 次数超限会由 POST_REWRITE_PHASE 拦截并返回 500,防止死循环。
FIND_CONFIG_PHASE:纯内部阶段,仅由 core 模块完成 location 匹配,不开放给第三方模块注册 handler。它像一道“闸门”,决定了后续所有阶段使用的配置上下文(server + location)。
PREACCESS / ACCESS / POST_ACCESS_PHASE:构成访问控制三段式。PREACCESS 做前置准备(如限流计数初始化),ACCESS 执行核心鉴权(IP 黑白名单、basic auth、JWT 校验等),POST_ACCESS 收尾(比如根据 ACCESS 结果统一返回 403/401)。只要 ACCESS 中任一 handler 返回 NGX_HTTP_FORBIDDEN,流程即刻中断并交由 POST_ACCESS 发送错误页。
CONTENT_PHASE:唯一允许真正输出响应体的阶段。静态文件服务、反向代理(proxy_pass)、FastCGI、Lua(content_by_lua*)等都挂载于此。它不关心权限或重写,只专注“把内容给出去”。若此处无 handler 处理(比如没配 proxy_pass 也没配 root),Nginx 默认返回 404。
LOG_PHASE:无论成功或失败,只要请求走到这里,就代表生命周期即将结束。access_log 写入、连接清理、内存释放都在此阶段完成。它不接受任何跳转,也不再产生响应——只是善后。
阶段间跳转由 checker 控制,不是简单线性
每个阶段背后都有一个专属的 checker 函数(如 ngx_http_core_rewrite_phase),它决定下一步动作:
- 继续遍历本阶段剩余 handler
- 直接跳到下一阶段开头
- 跳回某个 rewrite 阶段(例如重写后重新匹配 location)
- 终止流程并进入 LOG_PHASE
这种机制让 Nginx 在保持阶段顺序的前提下,支持内部重定向、try_files 回溯、认证失败重定向等复杂行为,而无需破坏整体状态机结构。
哪些阶段适合开发者介入
官方明确不建议往以下四个阶段添加自定义 handler:FIND_CONFIG_PHASE、POST_REWRITE_PHASE、POST_ACCESS_PHASE、TRY_FILES_PHASE。它们要么是 core 内部专用,要么逻辑高度固化。
推荐挂载点只有三个:
- PREACCESS_PHASE:做轻量预处理(如设置变量、记录时间戳)
- ACCESS_PHASE:实现核心业务鉴权逻辑
- CONTENT_PHASE:提供动态内容或转发决策
这三个阶段职责清晰、扩展安全、社区模块支持成熟,是定制开发最常使用的入口。











