Nginx反向代理中,Worker进程解析上游响应头经历四阶段:header parsing→internal representation→filtering→output preparation。解析在内存中完成,状态行与header字段被结构化存储于链表,经过滤重写后序列化为标准HTTP头块发送。

当 Nginx 作为反向代理运行时,Worker 进程在收到后端(如上游服务器)的响应后,并不会直接转发给客户端,而是先解析响应头(Response Headers),完成校验、过滤、重写等处理,再构建新的响应发往客户端。这个解析流程发生在内存中,由 Worker 进程内事件循环驱动,不涉及磁盘 I/O,关键在于 header parsing → internal representation → filtering → output preparation 四个阶段。
响应头的原始读取与分块识别
Worker 进程通过已建立的 upstream 连接(通常为 keepalive)接收后端数据流。响应头以 HTTP/1.x 状态行开头(如 HTTP/1.1 200 OK),随后是若干行 header 字段,以空行(\r\n\r\n)结束。Nginx 使用内部缓冲区(r->upstream->buffer)逐步接收字节,边收边解析:
- 状态行被解析为
r->upstream->headers_in.status和r->upstream->headers_in.status_line - 每行 header 被拆分为 name/value,忽略大小写归一化(如
Content-Type和content-type视为同一字段) - 遇到空行即判定 header 解析完成,后续字节进入 body 缓冲区
- 若响应使用
Transfer-Encoding: chunked,chunk 头部也会被识别并剥离,但 chunk 解码在 body 阶段进行,header 层不处理
Header 字段的内部结构化存储
解析后的 header 不以原始字符串形式保存,而是存入 r->upstream->headers_in 这个 ngx_table_elt_t * 链表中。每个字段对应一个结构体,包含 key、value、hash(用于快速查找)、skip(是否跳过输出)等字段。Nginx 内建了常见 header 的快捷访问指针,例如:
-
r->upstream->headers_in.content_length_n:已转换为整数的Content-Length值(若存在且合法) -
r->upstream->headers_in.last_modified_time:已解析的Last-Modified时间戳 -
r->upstream->headers_in.set_cookie:指向所有Set-Cookie头的链表(支持多值) - 未预定义的 header 仍保留在通用链表中,可通过
ngx_list_part遍历访问
Header 过滤与重写机制
解析完成后,Nginx 按注册顺序调用所有启用的 upstream header filter 模块(如 ngx_http_proxy_header_filter、ngx_http_headers_filter)。该阶段决定哪些 header 发送给客户端:
-
proxy_hide_header/proxy_pass_request_headers off:标记对应 header 的skip = 1,后续不再输出 -
proxy_set_header仅影响请求头;响应头重写需用proxy_hide_header + proxy_set_header组合,或通过 Lua/NJS 注入逻辑 -
add_header在此阶段后执行,添加的是“响应头”,而非“上游响应头”,二者存储位置和触发时机不同 - 某些模块会动态修改字段,如
ngx_http_gzip_filter在检测到Content-Encoding: gzip且未启用 gzip 时,会清除该头防止客户端误解析
响应头最终序列化与发送
经过所有 filter 处理后,Nginx 将有效 header 构建为标准 HTTP 响应头块(含状态行 + 合法 header 行 + 空行),写入输出缓冲区(r->out 或 r->upstream->out)。此时:
- 所有 header value 已做必要转义(如控制字符被丢弃)
- 重复的 header(如多个
Vary)默认保留全部(RFC 允许),除非模块显式合并 - 若启用
underscores_in_headers on,下划线字段也能被解析(但默认禁用,因多数后端不规范) - 整个 header 块作为单次 writev() 或 sendfile() 的一部分发出,无逐行 syscall 开销










