使用 proxy_pass 连接 Apache 时,Nginx 会忽略 Host 标头之前的 HTTP 标头

使用 proxy_pass 连接 Apache 时,Nginx 会忽略 Host 标头之前的 HTTP 标头

当 Nginx 发送以下请求时,Apache 无法获取“app_version”HTTP 标头。

我通常使用它apache_request_headers()来获取所有标题。我还检查了$_SERVER

GET /stuff HTTP/1.0
app_version: 1.0
Host: example.com

但是,当发送以下标头时,apache_request_headers()确实返回“app_version”HTTP 标头!

GET /stuff HTTP/1.0
Host: example.com
app_version: 1.0

问题是,我使用的是第三方 REST 客户端 (Retrofit),它似乎以随机顺序发送标头,因此我无法通过先发送 Host 标头来简单地解决这个问题。无论如何,我不明白为什么标头中包含下划线或标头的放置顺序会影响任何事情。 (标头格式与 HTTP 规范兼容)。 我想要一个针对当前问题的解决方案,而不是一个变通方法。

我有以下 Nginx 配置:

underscores_in_headers on;

location / {
   proxy_set_header Host $host;
   proxy_set_header X-Forwarded-Proto $scheme;
   proxy_set_header X-Real-IP  $remote_addr;
   proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

   proxy_pass_request_headers on;
   proxy_pass http://127.0.0.1:8080;
}

什么原因造成这种不一致?

答案1

尝试添加

proxy_set_header app_version $http_app_version;
underscores_in_headers on;

到配置。

可能underscores_in_headers这里只要设置就够了。

答案2

Tero Kilkanen 的回答是正确的。但是,您必须将其添加underscores_in_headers on;httpnginx conf 的部分,而不仅仅是您的server部分。

Nginx 在解析标头之前无法知道请求所针对的虚拟主机Host。因此,在标头之前解析的所有标头都Host在配置的“上下文”中解析。如果您在配置中http没有,则所有出现在标头之前且包含下划线的标头都被视为无效并被忽略。解析标头后,将激活属于与您的请求相对应的部分的配置指令。因此,如果您在-level 中有,则不会丢弃出现在标头之后且包含下划线的标头。underscores_in_headers on;httpHostHostserverunderscores_in_headers on;serverHost

答案3

同样的问题在这里,负载均衡器在 Host 标头之前添加了 X-Forwarded-For、-Port 和 -Proto 标头:

$ nc -l 443
GET / HTTP/1.1
X-Forwarded-For: x.x.x.x
X-Forwarded-Port: 443
X-Forwarded-Proto: https
Host: y.y.y.y:443
Connection: keep-alive

Nginx 永远不会填充 $proxy_add_x_forwarded_for 或 $http_x_forwarded_proto,这意味着它们被删除了。

此外,使用 curl 模拟 LB 确实会导致 nginx 正确填充它,并且 HOST 位于 x-fwd 标头之前:

GET /admin/extra-commands/ HTTP/1.1
Host: x.x.x.x
X-Forwarded-For: 1.2.3.4

我认为这是 nginx 的一个限制/错误

相关内容