nginx的proxy模块深度嵌入HTTP处理生命周期,在upstream阶段介入请求:先解析变量与后端地址,再重写URI、注入headers,最后通过事件驱动异步转发,并由upstream框架统一处理错误与重试。

nginx 的 ngx_http_proxy_module 并非独立运行,而是深度嵌入 HTTP 请求处理生命周期中,其执行本质是响应特定阶段(phase)的回调函数。理解它,关键不是看“模块怎么写”,而是看“请求在哪些环节被它介入、改写和转发”。
请求进入 upstream 阶段前:变量准备与后端地址解析
proxy 模块不直接处理读请求头或发响应,它的核心动作始于 NGX_HTTP_CONTENT_PHASE 之后的 NGX_HTTP_POST_CONTENT_PHASE 或更准确地说,在 upstream 初始化阶段(由 ngx_http_upstream_init_request 触发)。此时:
- 已解析完客户端请求行与头部,
$proxy_host、$proxy_port等 proxy 相关变量(如proxy_pass中含变量)被实时展开; - 若使用
proxy_pass http://backend/形式,nginx 会查找名为backend的 upstream 块,并调用对应 upstream.init_upstream 回调(通常是ngx_http_upstream_init_round_robin); - 若
proxy_pass是纯 URL(如proxy_pass http://127.0.0.1:8080/),则动态构造一个匿名 upstream,并初始化其 peer(后端节点)列表 —— 此时仅含一个固定地址。
构建 upstream request:重写 URI 与注入 headers
真正决定“发什么给后端”的逻辑集中在 ngx_http_proxy_create_request 函数中,它在 upstream 发起连接前被调用:
- 根据
proxy_redirect、proxy_set_header、proxy_pass_request_headers等指令,组装后端请求的 headers; - 按
proxy_pass配置重写原始 URI:
– 若proxy_pass以/结尾且 location 也以/结尾,则 location 路径被完全截掉,只保留 URI 后缀;
– 若proxy_pass不带路径(如http://s1),则原始 URI 全量透传;
– 若proxy_pass带具体路径(如http://s1/api),则 location 匹配部分被替换为该路径; - 最终生成的后端请求行(如
GET /api/v1/user HTTP/1.0)和 headers(包括 Host、X-Real-IP 等)全部存入r->upstream->request_bufs链表,等待发送。
连接与转发:异步 I/O 下的 buffer 管理
nginx 不同步阻塞等待后端响应,整个 proxy 流程基于事件驱动:
- 调用
ngx_event_connect_peer建立到后端的 TCP 连接(可能复用 keepalive 连接); - 连接就绪后,触发
ngx_http_upstream_send_request,将request_bufs写入 socket; - 后端响应到达时,由
ngx_http_upstream_process_header解析响应行与 headers,再由ngx_http_upstream_process_body流式接收 body; - 所有数据均经由 nginx 自研的 buffer 链表(
ngx_buf_t+ngx_chain_t)流转,支持内存/临时文件混合缓冲(受proxy_buffering控制); - 若启用 buffering,响应会先暂存再统一返回客户端;若关闭,则边收边转(streaming),但需注意后端响应必须合法 HTTP(否则无法解析 headers)。
错误与重试:upstream 框架统一兜底
proxy 模块本身不实现重试逻辑,而是依赖上游的 ngx_http_upstream_next 机制:
- 当连接失败、超时、收到无效响应或后端返回 5xx 且配置了
proxy_next_upstream时,upstream 框架自动选择下一个 peer; - 重试次数由
proxy_next_upstream_tries限制,重试间隔由proxy_next_upstream_timeout控制; - 最终失败时,由
ngx_http_upstream_finalize_request调用ngx_http_upstream_handle_502等函数,返回默认错误页或自定义 error_page。
proxy 模块的价值不在“做了什么”,而在“在正确的时间点,把正确的数据交给了 upstream 框架”。它把反向代理抽象成标准 upstream 行为,让负载均衡、健康检查、缓存等能力天然复用,这才是 nginx 架构精妙之处。










