nginx 无传统 eventloop,而是由每个 worker 进程基于 epoll 等 i/o 多路复用运行独立事件循环,驱动请求依次经过 11 个预定义 http 阶段,各阶段通过 handler 返回值控制流转,支持模块化扩展。

在 Nginx 中,并不存在传统意义上的“EventLoop”概念(如 Node.js 那样单线程、JS 主循环驱动的 EventLoop),而是基于多进程 + epoll/kqueue/iocp 等高效 I/O 多路复用机制,由 master-worker 架构下的每个 worker 进程独立运行一个事件驱动循环。这个循环才是 Nginx 请求处理的真正驱动力——它不断捕获就绪事件(连接建立、数据可读、写就绪等),并调度对应阶段的 handler。所谓“请求阶段转换”,本质是该事件循环在不同生命周期节点上,依据配置和状态,将请求依次推入预定义的 11 个 phase(阶段),每个阶段执行一组模块注册的 handler,形成有序、可扩展的处理流水线。
worker 进程的事件循环是阶段推进的底层引擎
Nginx 启动后,每个 worker 进程会进入一个无限循环(ngx_process_events_and_timers),其核心逻辑是:
- 调用
epoll_wait(Linux)等系统调用,等待 socket 事件就绪; - 遍历就绪事件队列,对每个事件执行绑定的回调(如
ngx_event_accept处理新连接,ngx_http_init_request初始化 HTTP 请求); - 一旦请求结构体(
ngx_http_request_t)创建完成,就立即启动“阶段机”:从NGX_HTTP_POST_READ_PHASE开始,按序执行各 phase 的 handler; - 某个 handler 可以主动中断当前阶段(如返回
NGX_AGAIN表示需等待后续 I/O)、跳转到下一阶段(ngx_http_core_run_phases自动推进),或终止请求(如返回NGX_HTTP_FORBIDDEN)。
11 个标准 HTTP 阶段构成可插拔的处理流水线
Nginx 将 HTTP 请求生命周期划分为固定顺序的 11 个阶段(定义在 ngx_http_core_module.c),每个阶段支持多个模块注册 handler,按配置顺序执行:
- NGX_HTTP_POST_READ_PHASE:刚读完请求头后,常用于 realip、geo 模块修正客户端地址;
-
NGX_HTTP_SERVER_REWRITE_PHASE:server 块内的 rewrite 指令(如
rewrite ... last); - NGX_HTTP_FIND_CONFIG_PHASE:内部阶段,根据 URI 匹配 location,不可注册 handler;
- NGX_HTTP_REWRITE_PHASE:location 块内 rewrite 指令,执行后会重新进入 FIND_CONFIG;
- NGX_HTTP_POST_REWRITE_PHASE:rewrite 结束后兜底检查,防止死循环(如未匹配到 location 则 404);
- NGX_HTTP_PREACCESS_PHASE:访问控制前预处理,如 limit_req、limit_conn;
- NGX_HTTP_ACCESS_PHASE:核心鉴权阶段,如 auth_basic、allow/deny、auth_request;
- NGX_HTTP_POST_ACCESS_PHASE:access 结果处理,如拒绝时统一返回错误页;
- NGX_HTTP_TRY_FILES_PHASE:try_files 指令专用阶段(若启用);
- NGX_HTTP_CONTENT_PHASE:内容生成阶段,proxy_pass、fastcgi_pass、index、static 文件服务等都在此;
- NGX_HTTP_LOG_PHASE:请求结束后的日志记录,总是执行(即使出错)。
阶段跳转不依赖“回调注册”,而由 handler 返回值与核心逻辑协同控制
阶段流转不是靠事件循环主动“推送”,而是由当前阶段所有 handler 执行完毕后,由 Nginx 核心函数 ngx_http_core_run_phases 判断下一步:
- handler 返回
NGX_OK:继续执行本阶段下一个 handler; - 返回
NGX_DECLINED:跳过本阶段剩余 handler,进入下一阶段; - 返回
NGX_AGAIN或NGX_DONE:暂停阶段机,等待 I/O 事件(如 upstream 响应到达)后恢复; - 返回 HTTP 状态码(如
NGX_HTTP_FORBIDDEN):立即终止流程,进入LOG_PHASE并返回响应; - 特殊指令(如
rewrite ... break)会直接设置r->phase_handler指向下个阶段起始位置,实现显式跳转。
第三方模块通过注册 phase handler 实现深度介入
开发者可通过 ngx_http_phase_handler_t 在任意阶段插入逻辑,例如:
- 在
PREACCESS_PHASE注册风控模块,解析请求头中的 token 并校验有效性; - 在
CONTENT_PHASE替换默认 content handler,实现动态 API 聚合; - 在
LOG_PHASE添加自定义日志字段(如上游耗时、缓存命中标识); - 注意:必须在
postconfiguration回调中调用ngx_http_core_post_rewrite_phase等宏注册,且 handler 函数需严格遵循返回值语义,否则破坏阶段机稳定性。











