
上一章我们介绍了 Nginx 负载均衡以及反向代理的基础知识。本章将继续深入,讲解 Nginx 反向代理模块相关指令的配置,以及反向代理不同阶段的缓存配置。我们将针对不同的应用场景进行优化配置,以提升访问性能,并通过具体案例帮助您快速掌握 Nginx 反向代理的配置方法。
在开始之前,我们先来回顾一下 Nginx 中 HTTP 协议反向代理请求处理的核心流程,这有助于我们更深刻地理解 Nginx 反向代理的工作机制,并在后续实践中相互印证。
Nginx 中 HTTP 反向代理流程详解
下图清晰地展示了 Nginx 中 proxy 模块进行反向代理的处理流程。它涵盖了从请求接收到连接复用的完整环节,包括缓存检查、上下游请求与响应的缓冲机制、负载均衡选择等。理解这一流程对于掌握 Nginx 的工作原理和进行有效的性能调优至关重要,特别是在处理像高并发这样的复杂场景时。

weiyigeek.top-Nginx中HTTP 反向代理流程图
流程解析:
- 触发阶段:反向代理在 Nginx 十一个处理阶段之一的
content 阶段生效。当配置了 proxy_pass 指令(其优先级高于 root 指令)时,反向代理流程在此触发。
- 缓存检查:流程开始后,首先检查是否有可用的缓存。如果缓存命中且有效,则直接返回响应,无需向上游服务器发起请求。
- 请求构造:若未命中缓存,则进入完整的反向代理流程。首先,根据客户端请求生成待发送给上游服务器的 HTTP 头部和包体。
- 请求体缓冲控制:通过
proxy_request_buffering 指令控制是否先将完整的客户端请求体缓冲后再处理。默认开启(on),Nginx 会先将请求体完整读入内存或磁盘。
- 开启场景:适用于上游服务并发处理能力弱于 Nginx 的场景,避免边收边发占用上游过多连接资源。
- 关闭场景:适用于上游服务对并发连接不敏感的场景,可实现流式转发,提升响应实时性。
- 负载均衡选服:根据配置的负载均衡算法(如轮询、IP哈希、最少连接等),从
upstream 块定义的服务器组中选择一个上游服务器。
- 建立连接:根据选中的服务器参数建立 TCP 连接。可配置连接超时、重试等行为。
- 发送请求:将请求发送到上游服务器。如果启用了
proxy_request_buffering,则一次性发送完整的请求体;否则采用边读边发的流式传输。
- 接收响应头:接收上游服务器返回的响应头部。
- 处理响应头:在接收到完整的响应头部后进行处理,同时变量
$upstream_header_time 会记录接收响应头所耗费的时间。
- 响应体缓冲控制:通过
proxy_buffering 指令控制如何向下游(客户端)发送响应。默认开启(on),Nginx 会先将上游的完整响应体接收并暂存于临时文件或内存中,再统一发送给客户端。
- 开启场景:快速接收上游响应以释放其连接,由 Nginx 独立控制向客户端的发送节奏,提高系统吞吐量。
- 关闭场景:采用流式传输,边接收上游响应边转发给客户端,适用于客户端网速与上游相近的场景。
- 缓存写入:响应发送完毕后,如果开启了缓存功能且当前响应符合缓存条件,则将其写入缓存系统。
- 连接管理:流程结束,根据配置决定是否关闭或复用与上游服务器的连接。通过
keepalive 机制复用连接可以显著提升后续请求的性能。
综上所述,完整的反向代理处理流程为:缓存检查 → 请求构造 → 包体接收控制 → 负载均衡选服 → 连接建立 → 请求发送 → 响应头接收 → 响应体缓冲控制 → 响应转发 → 缓存写入 → 连接管理。后续我们将围绕此流程详解各指令的具体用法。
0x01 Nginx 反向代理模块指令浅析
在 Nginx 官方文档中,http 和 stream 模块都包含 proxy 模块,即 ngx_http_proxy_module 和 ngx_stream_proxy_module。前者用于转发 HTTP、gRPC、WebSocket 等协议,后者用于处理 TCP、UDP 协议。本章我们重点了解 ngx_http_proxy_module 的常用指令,这是构建 Web 服务反向代理和网络架构的核心。
ngx_http_proxy_module 模块指令
HTTP 协议反向代理
在 Nginx 的 Content 阶段,proxy_pass 指令决定了请求由 ngx_http_proxy_module 模块处理。该模块默认编译进 Nginx,可通过 --without-http_proxy_module 选项禁用。
核心指令:proxy_pass
- 语法:
proxy_pass URL;
- 上下文:
location, if in location, limit_except
- 作用:设置代理服务器的协议、地址及可选的 URI。这是反向代理最核心的动作类指令。
生成发往上游的请求行与头部:
proxy_method:设置发往上游的 HTTP 方法。默认为传递客户端原始方法。
proxy_http_version:设置发往上游的 HTTP 协议版本。默认为 1.0,若需使用长连接(keepalive),必须设置为 1.1。
proxy_set_header:设置发往上游的请求头部。默认会设置 Host 为 $proxy_host,并关闭长连接 (Connection: close)。
proxy_pass_request_headers:控制是否将原始请求的头部传递给上游。默认为开启 (on)。
生成发往上游的请求体:
proxy_set_body:自定义发往上游的请求体内容。
proxy_pass_request_body:控制是否将原始请求体传递给上游。默认为开启 (on)。
温馨提示:
proxy_pass 指令中的 URL 参数可以是域名、IP地址(带端口)、Unix Socket 地址、upstream 块中定义的服务组名称,或使用 @ 命名的内部 location。也可以使用变量动态构建,如 $scheme、$host、$request_uri 等。
示例演示
-
定义上游服务器:在 Nginx 配置目录下创建 backend_server.conf,定义一个包含两个后端服务器的 upstream 组。
upstream backend {
zone backend_zone 64k; # 共享内存区,用于工作进程间同步负载信息
server 127.0.0.1:8011 weight=2; # 权重为2
server 127.0.0.1:8012;
keepalive 10; # 与上游保持最多10个空闲长连接
keepalive_timeout 60s;
}
-
定义反向代理服务:创建 proxy_server.conf,配置监听服务及不同的 location 规则。
-
场景一:proxy_pass 不带 URI
server {
listen 80;
server_name test.weiyigeek.top;
location / {
proxy_pass http://backend;
proxy_method POST; # 修改请求方法
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Connection ""; # 启用长连接
proxy_http_version 1.1;
proxy_set_header name 'weiyigeek'; # 自定义头部
proxy_set_body 'Hello World!'; # 自定义请求体
# proxy_pass_request_body off; # 可关闭原始请求体传递
}
}
此时,客户端请求的原始 URI 会原样传递给上游服务器。
-
场景二:proxy_pass 指定 URI
location /a {
proxy_pass http://backend/addurl;
# 其他头部设置...
}
当访问 /a/bb/cc 时,传递给上游的 URI 会替换为 /addurl/bb/cc。
-
场景三:使用 $request_uri 变量
location /b {
proxy_pass http://backend$request_uri;
# 其他头部设置...
}
此时会动态构建上游请求地址,URI 保持原样。
-
场景四:结合 rewrite 重写 URI
location ^~ /reg/ {
rewrite ^/reg(/|$)(.*) /$2 break;
proxy_pass http://backend;
# 其他头部设置...
}
访问 /reg/xxx 时,通过 rewrite 规则将 URI 重写为 /xxx 后再转发给上游。
配置验证
使用 nginx -s reload 重载配置后,通过 curl 命令验证上述配置:
$ curl http://test.weiyigeek.top/a/bb/cc?uid=1024
# 响应中 uri 显示为 /addurl/bb/cc,验证了路径替换
$ curl http://test.weiyigeek.top/b/cc/dd?id=1024
# 响应中 uri 显示为 /b/cc/dd,验证了变量传递
$ curl http://test.weiyigeek.top/reg/aa/bb/cc?id=1024
# 响应中 uri 显示为 /aa/bb/cc,验证了重写规则生效
重要提示:使用 proxy_pass 时,务必清楚是否配置了 URI 路径。带 URI 和不带 URI 的行为差异巨大(路径替换 vs. 路径传递),错误的配置可能导致上游服务器返回 404。应在测试环境中充分验证。
HTTP 协议反向代理中接收客户端请求处理
本小节重点讲解 Nginx 处理客户端请求体的机制,这是影响反向代理性能的关键环节。
核心指令与配置:
-
请求体缓冲开关:proxy_request_buffering
- 作用:控制是否在转发前完整接收客户端请求体。
on (默认):先完整接收请求体再转发。适用于客户端网速慢、需保护上游服务的场景。
off:边接收边转发(流式)。适用于内网高速环境,可降低 Nginx 自身开销。注意:一旦开始向上游发送 body,proxy_next_upstream 指令将失效,无法进行故障转移。
-
客户端请求体缓冲区配置 (属于 ngx_http_core_module):
client_body_buffer_size:设置读取请求体的缓冲区大小。默认 8k/16k。请求体超出缓冲区部分会写入临时文件。
client_body_in_single_buffer:是否将整个请求体保存在单个缓冲区中。建议在使用 $request_body 变量时开启,以减少复制操作。
client_body_in_file_only:是否强制将整个请求体存入磁盘文件。on 为始终存入,clean 为读取后删除,off 为尽量使用内存缓冲。
-
临时文件存储优化:client_body_temp_path
- 作用:定义存储请求体临时文件的目录,支持多级子目录以防止单目录文件过多导致 I/O 性能瓶颈。
- 示例:
client_body_temp_path /var/nginx/client_temp 1 2;
- 生成路径示例:
/var/nginx/client_temp/7/45/00000123457
-
超时与大小限制:
client_body_timeout:定义读取请求体的超时时间,默认 60s。超时返回 408 错误。
client_max_body_size:定义客户端请求体的最大允许大小,默认 1m。超出返回 413 错误。对于文件上传服务,需根据业务调大此值。
总结:Nginx 对客户端请求体的处理策略直接影响其作为反向代理的性能与稳定性。在实际的运维生产环境中,需要根据客户端网络状况、上游服务处理能力及磁盘 I/O 特性,综合调整 proxy_request_buffering 与 client_body_* 系列指令,以达到最佳性能。
|