Nginx | HTTP 反向代理:对上游服务端返回响应处理实践

知识是人生的灯塔,只有不断学习,才能照亮前行的道路

📢 大家好,我是 WeiyiGeek,一名深耕安全运维开发(SecOpsDev)领域的技术从业者,致力于探索DevOps与安全的融合(DevSecOps),自动化运维工具开发与实践,企业网络安全防护,欢迎各位道友一起学习交流、一起进步 🚀,若此文对你有帮助,一定记得点个关注⭐与小红星❤️或加入到作者知识星球『 全栈工程师修炼指南』,转发收藏学习不迷路 😋 。

HTTP 协议反向代理中与上游服务端返回响应处理

描述:前面已经讲解,客户端 与 Nginx 服务器建立连接,发送请求到 Nginx 服务端,Nginx 服务端再将请求转发给上游服务等相关指令参数,本节将继续讲解如何接收并处理来自上游的HTTP响应的相关指令。

通过前面回顾的反向代理请求响应流程可知,Nginx 接受上游响应分为两个阶段,一是先接收并处理响应头部(header)二是处理响应包体(body)。另外响应的接收由 Nginx 的 upstream 框架负责,而响应头部的处理由具体的反向代理模块完成,如 proxy、gRPC、CGI、UWSGI 等

另外,响应内容在发送给客户端前,还必须经过 Nginx 过滤模块的处理,同样在使用 Nginx 作为反向代理时,上游服务返回的响应头也会被 header_filter 等过滤模块处理,例如添加额外的头部信息、修改内容等。

温馨提示:若文章代码块中存在乱码或不能复制,请联系作者,也可通过文末的阅读原文链接,加入知识星球中阅读,原文链接:https://articles.zsxq.com/id_fkims9wlo8ww.html

指令参数

1.接收处理上游服务端响应头部阶段

  • proxy_buffer_size 指令用于设置读取上游响应头部时使用的缓冲区大小,默认值是4k或8k取决于平台。如果上游服务器返回的响应头超过了此大小,则请求无法被正确处理,并会在日志中记录中出现 upstream sent too big header 错误信息。
go 复制代码
Syntax: proxy_buffer_size size;
Default: proxy_buffer_size 4k|8k;
Context: http, server, location
  • proxy_ignore_headers 指令用于忽略(禁用)上游服务器响应头中的某些特殊功能字段,例如 X-Accel-Redirect, X-Accel-Limit-Rate 等.这对于防止某些特定的头部信息被传递给客户端非常有用,特别是在反向代理场景中,上游服务可能会发送特定头部来控制 Nginx 行为的功能,例如:

    • X-Accel-Redirect: 允许上游服务指定内部重定向路径,由 Nginx 执行请求跳转。

    • X-Accel-Limit-Rate: 允许上游服务控制Nginx读取响应的速率,等同于 limit_rate 指令。

    • X-Accel-Buffering: 允许上游服务控制是否缓存上游的响应,等同于 proxy_buffering 指令。

    • X-Accel-Charset: 允许上游服务指定响应内容的字符集,等同于 Content-Type 头部制定的 Charset 字符集。

    • X-Accel-Expires: 允许上游服务指定缓存过期时间,单位为秒,以@开头的表示一天某个时刻,此外还有一些与缓存相关的头部信息,例如:"Expires", "Cache-Control", "Set-Cookie" (0.8.44), and "Vary" (1.7.7) 等

go 复制代码
Syntax: proxy_ignore_headers field ...;
Default: ---
Context: http, server, location
  • proxy_hide_header 指令对于上游响应头中的某些字段进行隐藏不传递,实际默认情况下不会传递字段有 "Date","Server","X-Pad"和"X-Accel-." 等,这对于防止敏感或不必要的头部信息被传递给客户端非常有用;相反如果需要允许传递字段,则可以使用 proxy_pass_header 指令(后续讲解)。

    • Date: 由 ngx_http_header_filter_module 过滤模块处理,表示上游服务生成响应的时间,但 Nginx 会将其替换为发送响应头部时间。

    • Server: 由 ngx_http_header_filter_module 过滤模块处理,表示上游服务器的标识,但 Nginx 会将其替换为自身版本信息。

    • X-Accel-: 用于控制 Nginx 行为,即内部重定向和缓存控制等特殊用途的头部信息,仅 Nginx 识别使用,不会被传递给客户端。

    • X-Pad: 由 Apache 服务器特有的头部,用于避免浏览器 Bug 所需,已被废弃。

go 复制代码
Syntax: proxy_hide_header field;
Default: ---
Context: http, server, location
  • proxy_pass_header: 允许从代理服务器向客户端传递禁用的头字段。
go 复制代码
Syntax: proxy_pass_header field;
Default: ---
Context: http, server, location
  • proxy_cookie_domain 指令用于重写上游响应中的 Set-Cookie 头部字段的 domain 值,这对于跨域资源共享(CORS)场景非常有用。
go 复制代码
Syntax: proxy_cookie_domain off;
        proxy_cookie_domain domain replacement;
Default: proxy_cookie_domain off;
Context: http, server, location
# 示例
proxy_cookie_domain localhost example.org;
proxy_cookie_domain www.$host $host;
proxy_cookie_domain ~\.(?P<sl_domain>[-0-9a-z]+\.[a-z]+)$ $sl_domain;
  • proxy_cookie_path 指令用于重写上游响应中的 Set-Cookie 头部字段的 path 值,这对于跨域资源共享(CORS)场景非常有用。
go 复制代码
Syntax: proxy_cookie_path off;
        proxy_cookie_path path replacement;
Default: proxy_cookie_path off;
Context: http, server, location

# 示例
proxy_cookie_path /two/ /;
proxy_cookie_path $uri /some$uri;
proxy_cookie_path ~*^/user/([^/]+) /u/$1;
  • proxy_redirect 指令用于重写上游响应中的 Location, RefreshURI 重定向头部字段。
go 复制代码
Syntax: proxy_redirect default;
        proxy_redirect off;
        proxy_redirect redirect replacement;
Default: proxy_redirect default;
Context: http, server, location
# 示例
# 上游响应返回:http://localhost:8000/two/some/uri/
# Nginx 转发给客户端:http://weiyigeek.top/one/some/uri/
proxy_redirect http://localhost:8000/two/ http://weiyigeek.top/one/;
proxy_redirect http://localhost:8000/ http://$host:$server_port/;
proxy_redirect ~*/user/([^/]+)/(.+)$  http://$1.weiyigeek.top/$2;

2.接收处理上游服务端响应包体阶段

  • proxy_buffering 指令用于控制是否先完整接收上游的包体再转发给客户端, 默认情况是开启的,因为通常情况上游服务器处于内网,但会增加网络带宽消耗和延迟。如果设置为 off,则响应会直接转发给客户端,而不会在 Nginx 服务器上进行缓冲处理,这对于实时流媒体传输等场景非常有用,以及在大包体场景避免长时间等待。另外,如果上游服务器响应头中带有 X-Accel-Buffering: yes|no,则会覆盖此设置可达同等效果。
go 复制代码
Syntax: proxy_buffering on | off;
Default: proxy_buffering on;
Context: http, server, location
  • proxy_buffers 指令用于用于设置用于缓存上游响应 body 的内存缓冲区数量和大小,默认值是8个4k(32k)8个8k(64k)的缓冲区(取决于平台),若响应 body 小于等于可用内存缓冲区总量,则直接在内存缓冲区中缓存,不写入磁盘,否则需将部分内容写入临时磁盘文件。
go 复制代码
Syntax: proxy_buffers number size;
Default: proxy_buffers 8 4k|8k;
Context: http, server, location

当启用了对来自代理服务器的响应进行缓冲时,如果整个响应不适合由 proxy_buffer_sizeproxy_buffers指令设置的缓冲区,则可以将部分响应保存到临时文件中,下述由三个关键指令用于控制磁盘写入。

  • proxy_max_temp_file_size 指令用于设置写入临时文件的最大大小,默认值是1024m。如果响应体的大小超过此限制,则将剩余部分直接发送给客户端,而不是存储在磁盘上。

  • proxy_temp_file_write_size 指令用于设置写入临时文件时使用的缓冲区大小,默认值是8k或16k(取决于平台)。

  • proxy_temp_path 指令用于设置临时文件的存储路径及子目录层级结构,与client_body_temp_path 指令类似,目录层级有助于分散文件数量,防止单个目录下文件过多导致系统性能下降。

go 复制代码
Syntax: proxy_max_temp_file_size size;
Default: proxy_max_temp_file_size 1024m;
Context: http, server, location

Syntax: proxy_temp_file_write_size size;
Default:  proxy_temp_file_write_size 8k|16k;
Context:  http, server, location

Syntax: proxy_temp_path path [level1 [level2 [level3]]];
Default: proxy_temp_path proxy_temp;
Context:  http, server, location
  # 示例: proxy_temp_path /spool/nginx/proxy_temp 1 2;
  # 结果:/spool/nginx/proxy_temp/7/45/00000123457

此外,Nginx 在启用缓冲的情况下,允许更早地将已接收的部分响应发送给客户端,例如:对于一个 1G 的文件响应,可通过该指令实现边接收边发送,提升用户体验。

  • proxy_busy_buffers_size 指令用于限制在响应尚未完全读取时可忙碌向客户端发送响应的缓冲区的总大小。默认值是8k16k(取决于平台);同时,其余的缓冲区可以用于阅读响应,如果需要,还可以将部分响应缓冲到临时文件中;简单来说:当累计接收到指定大小的数据(如 8K或 16K )后,即可开始向客户端转发,而不必等待全部接收完成,注意此参数,不能大于 proxy_buffers 指令设置的缓冲区大小。
go 复制代码
Syntax: proxy_busy_buffers_size size;
Default: proxy_busy_buffers_size 8k|16k;
Context:  http, server, location

3.接收上游服务端响应超时及速度控制

  • proxy_read_timeout 指令用于设置读取上游响应的超时时间,默认值是60s。如果在此时间内没有完全接收到响应,则连接将被关闭并返回错误信息给客户端,属于 TCP 层控制参数。
go 复制代码
Syntax: proxy_read_timeout time;
Default: proxy_read_timeout 60s;
Context: http, server, location
  • proxy_limit_rate 指令用于限制从上游服务器读取数据的速率, 速率以每秒字节数为单位指定, 默认值是0(无限制)。这对于控制带宽使用、防止单个客户端占用过多资源非常有用,其与客户端侧的 limit_rate 指令类似,但作用方向相反。特别注意:仅当启用了来自代理服务器的响应缓冲时,此限制才有效。
go 复制代码
Syntax: proxy_limit_rate rate;
Default: proxy_limit_rate 0;
Context: http, server, location

4.接收上游响应包体的持久化机制

  • proxy_store 指令允许将文件保存到磁盘,若设置为 on 表示启用,其保存路径对应于指令 alias 或 root 的文件,或者想
go 复制代码
Syntax: proxy_store on | off | string;
Default: proxy_store off;
Context: http, server, location
  • proxy_store_access 指令用于设置保存到磁盘的文件的访问权限,默认值是 user:rw;
go 复制代码
Syntax: proxy_store_access users:permissions ...;
Default: proxy_store_access user:rw;
Context: http, server, location

实践示例

示例1.演示 Nginx 在反向代理中如何处理上游服务响应头部示例。

  • 步骤 01.在 213 主机(openresty/1.27.1.1)搭建一个简单的上游服务,监听端口为 8010,用于演示 Nginx 如何处理响应头部。
go 复制代码
# 10.20.172.213 主机
vim /usr/local/openresty/nginx/conf/nginx.conf
http {
  ...
  server {
    listen 8010;
    server_name localhost _;
    default_type text/plain;
    root html;
    location / {
      add_header X-Custom-Name 'weiyigeek';
      add_header X-Custom-Url 'www.weiyigeek.top';
      add_header X-Accel-Limit-Rate 10;  # 限速 Nginx 读取 10 bytes/s
    }
  }
  ...
}

# 在 /usr/local/openresty/nginx/html/ 目录下创建下载文件
$ ls -alh `pwd`/
-rw-r--r-- 1 root root 61K 2025年 5月26日 /usr/local/openresty/nginx/html/C9C867AB833A4C7A869E302411DE8078.zip
$ echo'Hello, this is upstream server response!' >> /usr/local/openresty/nginx/html/index.txt
  • 步骤 02.在 214 主机的 Nginx 配置目录中创建 backend_server.conf 文件,定义 upstream 服务组。
go 复制代码
tee /usr/local/nginx/conf.d/backend_server.conf <<'EOF'
# 创建上游服务器
upstream backend_server {
# 定义共享内存区,用于在工作进程间同步负载信息,可根据后端服务器数量调整。
  zone backend_zone 64k;

# 单个上游服务组,此处只是演示,实际应用中可根据实际需求配置多个上游服务器。
  server 10.20.172.213:8010;

# 设置与上游服务器的长连接,最多保持10个空闲的保活连接。
  keepalive 10;  
  keepalive_timeout 60s; # 设置与上游服务器的长连接,空闲连接的超时时间。
}
EOF
  • 步骤 03.在 214 主机的 Nginx 配置目录中创建 proxy_server_response_header.conf 文件,
go 复制代码
# 创建监听用于反向代理
tee /usr/local/nginx/conf.d/proxy_server_response_header.conf <<'EOF'
server {
  listen 80;
  server_name test.weiyigeek.top;
  access_log /var/log/nginx/test.log main;
  error_log test.error.log info;

  location / {
    proxy_pass http://backend_server;
    # 设置请求方法
    proxy_method GET;

    # 设置请求头部
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

    # 启用长连接
    proxy_set_header Connection "";
    proxy_http_version 1.1;
    
    # 指定隐藏上游服务器响应头部字段
    proxy_hide_header X-Custom-Name;

    # 允许透传上游服务器响应中的 Server 头部字段
    proxy_pass_header Server;

    # 启用或禁用上游响应的 X-Accel-Limit-Rate 头部字段验证其效果
    proxy_pass_header X-Accel-Limit-Rate;
    # proxy_ignore_headers X-Accel-Limit-Rate;
  }
}
EOF

步骤 04.重启 Nginx 服务,使用 curl 命令测试上游服务响应头部是否被正确处理,执行结果如下图所示

go 复制代码
# 注释 # proxy_ignore_headers X-Accel-Limit-Rate; 时结果
nginx -s reload
time curl -I http://test.weiyigeek.top/C9C867AB833A4C7A869E302411DE8078.zip

  HTTP/1.1 200 OK
  Date: Wed, 10 Dec 2025 03:34:47 GMT
  Content-Type: application/zip
  Content-Length: 61589
  Connection: keep-alive
  Server: openresty/1.27.1.1
  Last-Modified: Mon, 26 May 2025 02:36:39 GMT
  ETag: "6833d3b7-f095"
  X-Custom-Url: www.weiyigeek.top
  X-Accel-Limit-Rate: 10
  Accept-Ranges: bytes


  real    0m30.042s
  user    0m0.005s
  sys     0m0.003s


# 注释 proxy_pass_header X-Accel-Limit-Rate; 时结果
# 取消注释 proxy_ignore_headers X-Accel-Limit-Rate; 时结果
nginx -s reload
time curl -I http://test.weiyigeek.top/C9C867AB833A4C7A869E302411DE8078.zip
  HTTP/1.1 200 OK
  Date: Wed, 10 Dec 2025 03:38:32 GMT
  Content-Type: application/zip
  Content-Length: 61589
  Connection: keep-alive
  Server: openresty/1.27.1.1
  Last-Modified: Mon, 26 May 2025 02:36:39 GMT
  ETag: "6833d3b7-f095"
  X-Custom-Url: www.weiyigeek.top
  Accept-Ranges: bytes


  real    0m0.007s
  user    0m0.002s
  sys     0m0.004s

time curl -i http://test.weiyigeek.top/index.txt


weiyigeek.top-验证Nginx对于上游头部响应的处理图

示例2.演示 Nginx 在反向代理中如何持久化存储客户端请求,以及上游服务响应内容到磁盘文件。

  • 步骤 01.在 214 主机的Nginx 配置文件中,分布定义 8011 和 8012 服务用于后续演示反向代理转发及负载均衡。
go 复制代码
# 编辑主配置文件,添加 include 指令,引入自定义配置文件目录。
vim /usr/local/nginx/conf/nginx.conf
....
include /usr/local/nginx/conf.d/*.conf;
....

# 创建测试文件到 html 目录下
mkdir -vp /usr/local/nginx/html/{8011,8012}
echo"Hello, this is 8011 server response!" > /usr/local/nginx/html/8011/index.txt
echo"Hello, this is 8012 server response!" > /usr/local/nginx/html/8012/index.txt
chown -R nginx:nginx /usr/local/nginx/html/*

# 创建测试服务器配置文件目录,并写入两个监听服务器的配置。
mkdir /usr/local/nginx/conf.d/
tee /usr/local/nginx/conf.d/server.conf <<'EOF'
server {
  listen 8011;
  server_name localhost _;
  default_type text/plain;
  root html/8011;  # 关键点,此处为测试配置文件目录。
  location / {
    autoindex on;
  }

  location /test {
    return 200 'From 8011 server response!\nrequest: $request\nhost: $host\nuri: $uri\nrequest_uri: $request_uri\nmethod: $request_method\nhttp_name: $http_name\nrequest_body: $request_body\n';
  }
}

server {
  listen 8012;
  server_name localhost _;
  default_type text/plain;
  root html/8012;  # 关键点,此处为测试配置文件目录。
  location / {
    autoindex on;
  } 
  location /test {
    return 200 'From 8012 server response!\nrequest: $request\nhost: $host\nuri: $uri\nrequest_uri: $request_uri\nmethod: $request_method\nhttp_name: $http_name\nrequest_body: $request_body\n';
  }
}
EOF

步骤 02.在 214 主机的 Nginx 配置目录中创建 backend_server.conf 文件,定义 upstream 服务组。

go 复制代码
tee /usr/local/nginx/conf.d/backend_server.conf <<'EOF'
# 创建上游服务器
upstream backend {
# 定义共享内存区,用于在工作进程间同步负载信息,可根据后端服务器数量调整。
  zone backend_zone 64k;

# 缺省使用轮询的负载均衡算法
  server 127.0.0.1:8011 weight=2;  # 权重为2表示,轮询三次中有两次命中此上游服务器
  server 127.0.0.1:8012;

# 设置与上游服务器的长连接,最多保持10个空闲的保活连接。
  keepalive 10;  
  keepalive_timeout 60s; # 设置与上游服务器的长连接,空闲连接的超时时间。
}
EOF

步骤 03.在 214 主机的 Nginx 配置目录中创建 proxy_server_store.conf 文件,定义反向代理服务并持久化上游发送过来的响应内容到磁盘文件中。

go 复制代码
# 创建存放对于上游服务器响应持久化数据目录以及权限设置
mkdir -vp /var/tmp/nginx/proxy_store
chown -R nginx:nginx /var/tmp/nginx/proxy_store

# 创建监听用于反向代理
tee /usr/local/nginx/conf.d/proxy_server_store.conf <<'EOF'
server {
  listen 80;
  server_name test.weiyigeek.top;
  access_log /var/log/nginx/test.log main;
  error_log test.error.log info;

# 将整个客户端请求主体保存在磁盘文件中,而非直接保存在内存中。
  client_body_in_file_only on;
# 客户端请求主体的临时文件存储路径,使用层级结构有助于分散文件数量。
  client_body_temp_path /var/tmp/nginx/client_temp 1 2;


  location / {
    proxy_pass http://backend;
    # 设置请求方法
    proxy_method GET;

    # 设置请求头部
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

    # 启用长连接
    proxy_set_header Connection "";
    proxy_http_version 1.1;
    
    # 启用持久化存储响应内容到磁盘文件。
    root  /var/tmp/nginx/proxy_store;
    proxy_store        on;
    proxy_store_access user:rw group:rw all:r;

    # 设置接收上游服务器响应缓存
    proxy_buffers 8 4k;
    proxy_busy_buffers_size 8k;
    proxy_temp_path    /var/tmp/nginx/proxy_temp 1 2;
  }
}
EOF

温馨提示: 在实践时如果请求报 403 错误,请检查 nginx 用户权限是否对 root 指令指定的目录有读写权限。

步骤 04.配置完成后先执行 nginx -t 检查配置文件语法正确性,然后再执行 nginx -s reload 重新加载配置, 最后使用 curl 命令测试客户端上报的 body 以及 上游响应的 body 是否持久化存储到磁盘文件中。

go 复制代码
$ curl -X POST -d 'Client Request 1 by test.weiyigeek.top' http://test.weiyigeek.top/index.txt
Hello, this is 8011 server response!

$ curl -X POST -d 'Client Request 2 by test.weiyigeek.top' http://test.weiyigeek.top/index.txt
Hello, this is 8012 server response!

$ tree /var/tmp/nginx/


weiyigeek.top-测试客户端以及服务端持久化存储到磁盘文件图

至此,我们介绍了反向代理是怎样接收处理来之上游服务器的 Header 头部和 Body 包体及其相关指令,然后演示了如何针对上游服务响应头进行操作过滤处理,最后演示如何对客户端请求 Body 和上游服务器响应 Body 作持久化存储。

END

加入:作者【全栈工程师修炼指南】知识星球

『 全栈工程师修炼指南』星球,主要涉及全栈工程师(Full Stack Development)实践文章,持续更新包括但不限于企业SecDevOps和网络安全等保合规、安全渗透测试、编程开发、云原生(Cloud Native)、物联网工业控制(IOT)、人工智能Ai,从业书籍笔记,人生职场认识等方面资料或文章。

Q: 加入作者【全栈工程师修炼指南】星球后有啥好处?

✅ 将获得作者最新工作学习实践文章以及网盘资源。

✅ 将获得作者珍藏多年的全栈学习笔记(需连续两年及以上老星球友,也可单次购买)

✅ 将获得作者专门答疑学习交流群,解决在工作学习中的问题。

✅ 将获得作者远程支持(在作者能力范围内且合规)。

获取:作者工作学习全栈笔记

作者整理了10年的工作学习笔记(涉及网络、安全、运维、开发),需要学习实践笔记的看友,可添加作者微信或者回复【工作学习实践笔记】,当前价格¥299,除了获得从业笔记的同时还可进行问题答疑以及每月远程技术支持,希望大家多多支持,收获定大于付出!

知识推荐 往期文章

若文章对你有帮助,请将它转发给更多的看友,若有疑问的小伙伴,可在评论区留言你想法哟 💬!

相关推荐
Data_Journal7 小时前
Puppeteer vs. Playwright —— 哪个更好?
运维·人工智能·爬虫·媒体·静态代理
bj_zhb7 小时前
Python 内置的 HTTP 服务
开发语言·python·http
一只懒鱼a7 小时前
搭建kafka集群(安装包 + docker方式)
运维·容器·kafka
扫描电镜7 小时前
从 G1 到 G7:台式扫描电镜在稳定性与自动化上的技术演进
运维·人工智能·自动化
wanhengidc7 小时前
电脑端 云手机都有哪些注意事项
运维·服务器·安全·智能手机·云计算
2022.11.7始学前端7 小时前
n8n第十三节 三个节点测试技巧
运维·服务器·n8n
沧澜sincerely7 小时前
WebSocket 实时聊天功能
网络·websocket·vue·springboot
RedMery7 小时前
Ubuntu切换wayland和x11
linux·运维·ubuntu
专业开发者7 小时前
思科以终端产品解决方案提供商的身份实现效能提升
运维·服务器·网络