nginx将http请求处理严格划分为11个有序阶段:postread、server-rewrite、find-config、rewrite、post-rewrite、preaccess、access、postaccess、try-files、content、log,各阶段职责明确、支持模块介入,构成可预测、可扩展、易调试的流水线。

Nginx 处理一个 HTTP 请求不是简单地从头到尾顺序执行,而是被严格划分为 11 个有序、职责分明的阶段(phases)。每个阶段在请求生命周期中承担特定任务,模块可注册处理器介入,从而实现精细控制和灵活扩展。理解这些阶段,是排查配置异常、设计访问策略或开发模块的关键。
核心阶段顺序与关键作用
这 11 个阶段按执行先后固定排列,构成 Nginx 请求处理的骨架:
-
postread:请求行和头部读取完成后立即触发。典型用途是修正客户端真实 IP,比如 realip 模块解析
X-Forwarded-For或 Proxy Protocol 头。 -
server-rewrite:匹配 server 块后、查找 location 前执行。用于 server 级别的重写指令(如
rewrite),不影响后续 location 匹配逻辑。 - find-config:纯内部路由阶段。根据 Host、URI、SSL 参数等精确匹配到具体 server 和 location 块。此阶段无模块可介入。
-
rewrite:在已匹配的 location 内执行 rewrite 指令。支持多次重写;使用
last触发内部重定向,break则终止重写流程。 -
post-rewrite:判断 rewrite 是否导致内部跳转。若为
last,则重新进入 find-config 阶段;否则继续向下推进。 -
preaccess:访问控制前的准备阶段。限流模块(如
limit_req)在此做速率检查的初始化和前置判定。 -
access:权限控制主战场。IP 白名单(
allow)、黑名单(deny)、基础认证(auth_basic)、连接限制(limit_conn)均在此生效。 - postaccess:access 执行完毕后的收尾动作,例如记录拒绝详情、触发审计钩子或清理临时状态。
-
try-files:尝试按顺序查找静态资源(如
try_files $uri $uri/ /index.html)。任一命中即交由 content 阶段输出;全部失败则移交 content 默认 handler(如proxy_pass)。 -
content:响应内容生成的核心阶段。由具体 handler 承担:static 模块返回文件、
proxy_pass转发、fastcgi_pass交给 PHP-FPM 等。 -
log:请求处理结束(无论成功或出错)后必经阶段。确保
access_log和error_log不遗漏任何请求。
阶段跳转与常见依赖逻辑
阶段之间并非线性单向流动,存在明确的跳转机制:
- rewrite 中的
last会引发post-rewrite → find-config循环,相当于一次内部重定向;break则跳过后续 rewrite,直接进入 post-rewrite。 - try-files 查找不到匹配项时,不会直接返回 404,而是把控制权交给 content 阶段——这意味着即使没配
try_files,只要 location 下有proxy_pass,请求仍会被转发。 - access 阶段拒绝请求(如 IP 被 deny)会跳过 try-files 和 content,直接进入 log 阶段并返回 403。
- 所有阶段均可被第三方模块(如 OpenResty 的 Lua 模块)通过
access_by_lua*、content_by_lua*等指令挂载逻辑,但必须符合所处阶段的语义约束。
为什么阶段模型重要
这种分阶段设计带来三方面实际价值:
- 可预测性:每个模块知道自身逻辑会在哪个环节生效,避免行为冲突(例如 access 控制一定早于 content 输出)。
-
可调试性:配合
error_log debug可清晰看到请求流经哪些阶段、哪个模块介入、是否跳转,极大简化排障过程。 - 可组合性:不同功能模块(限流、鉴权、缓存、日志)各司其职,彼此解耦,便于叠加使用而不互相干扰。
掌握这 11 个阶段,就掌握了 Nginx 行为的底层节奏。它不是抽象概念,而是每次请求真实走过的路径。











