nginx的proxy_set_header设置

nginx proxy_set_header

简述

以前一直没有太关注 nginx 的 proxy_set_header 这个参数;

直到最近我的遇到一个事情, 发现配置的 header 传递不到后端服务器去了,
排查了一下, 才发现这里有几个有个巨大的陷阱

简述结论:

  1. location 内要么不配置 proxy_set_header, 要么就把所有的外部 proxy_set_header 项都再配置一遍;
  2. 有下划线的 header 会被默认删除

限制一: proxy_set_header 的继承和默认值

一、location 内的 proxy_set_header 的继承开关

是否继承外部的 proxy_set_header 值, 在 location 里面有一个开关;

就是这个 location 内是否存在一个 proxy_set_header 定义;

如果有一个或更多, 则关闭继承; 一个都没有, 则继承开启

二、proxy_set_header 的默认值

location 块有 2 个默认的 proxy_set_header 配置, 即
proxy_set_header Host $proxy_host;
proxy_set_header Connection close;

$proxy_host 就是 proxy_pass 所指向的地址(域名或ip地址);
Connection 的目的是主动关闭与后端的连接;

无论内部是否有 proxy_set_header, 这2个值都是有的; 除非:

  1. 内部把这2个值给修改了
  2. 外部有定义 且继承有效时 继承了过来;

举几个例子

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
server {
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

    location ~/api/v0/(.*) {
        proxy_pass http://10.3.0.3;
    }
}

server {
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

    location ~/api/v1/(.*) {
        proxy_pass http://10.3.0.3;
    }
    location ~/api/v2/(.*) {
        proxy_pass http://10.3.0.3;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
    location ~/api/v3/(.*) {
        proxy_pass http://10.3.0.3;
        proxy_set_header Host $host;
        proxy_set_header X-Req-Ip $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_http_version 1.1;
        proxy_set_header Connection "";
    }
}

v0 接口因为内部没有 proxy_set_header,所以使用的 继承+默认值;
且继承来的值没有覆盖 2 项默认值; 所以到上游时有 4 个 header;

1
2
3
4
   Host: 10.3.0.3
   X-Real-IP: 120.230.102.100
   X-Forwarded-For: 120.230.102.100
   Connection: close

v1 接口因为内部没有 proxy_set_header,所以使用的 继承+默认值;
但因为继承来的外部 Host 覆盖了内部的 1 个默认值;
所以内部只有一个默认值 Connection: close 会有效;
此时发给上游的请求中, header 如下

1
2
3
4
    Host: x.x.x.x
    X-Real-IP: 120.230.102.100
    X-Forwarded-For: 120.230.102.100
    Connection: close

v2 接口因为内部有 一个 proxy_set_header,所以继承被关闭了;
于是只有 2 个默认值 + 自定义的一项 xff, 于是到上游只有 3 个 header 值;

1
2
3
    Host: 10.3.0.3
    X-Forwarded-For: 120.230.102.100
    Connection: close

v3 接口内有多个 proxy_set_header 所以继承是关闭的; 且通过内部定义覆盖了 2项默认值;
此时发给上游的请求中, header 如下
注意这里因为 Connection 是空值, 默认会被删除, 所以只有 3 项

1
2
3
    Host: x.x.x.x
    X-Req-Ip: 120.230.102.100
    X-Forwarded-For: 120.230.102.100

所以结论是, 要么 location 内不要配置 proxy_set_header, 要么就把所有的项目都配置一遍;

说明: 这里并没有考虑其它如 User-Agent, Accept, Accept-Encoding 这些 header,
因为这些都是属于客户端来时有就转发, 没有也不会影响请求转发;

限制二: 带有短横线的header项不转发

1
proxy_set_header app_name "nginx1";

例如这种就默认不会被转发到后端去,

如果确实需要将这个带下划线的 header 转过去, 需要在 http 块进行配置

1
2
3
http{
    underscores_in_headers on;
}

网上查询到的说法是:
丢弃的原因是为了避免在将 header 映射到 CGI 变量时混淆,因为在此过程中,破折号和下划线都映射到了下划线;
所以默认就给丢弃了。

一般情况下 转发到上游服务器时,报文头的默认变化

  1. 删除所有空值的报文头
  2. 包含下划线的报文头会被丢弃
  3. Host 报文头会被重写为 $proxy_host 变量值
  4. Connterction 报文头会被修改为 close
  5. http1.1 的请求会被修改为 http1.0, 如果需要 1.1 需要单独指定 proxxy_http_version 1.1;
Licensed under CC BY-NC-SA 4.0
转载或引用本文时请遵守许可协议,知会作者并注明出处
不得用于商业用途!
最后更新于 2022-12-10 00:00 UTC