在使用proxy_pass时如何在nginx中添加响应头?

134

我想为nginx后端服务器返回的响应添加自定义头信息。

add_header可以用于nginx处理的响应,但是在使用proxy_pass时无效。


所以你将请求传递给代理,该代理设置响应,并且在将其发送给用户之前,您希望在此响应中添加自定义标头,是这样吗? - Michał Kupisiński
5个回答

223

add_header 带有和不带有 proxy_pass 一样的效果。今天我刚好设置了一个使用该指令的配置。不过,我必须承认我在没有确切记得原因的情况下也曾经努力过进行此类设置。

现在我的配置已经可以工作,并包含以下内容(和其他内容):

server {
    server_name  .myserver.com
    location / {
        proxy_pass  http://mybackend;
        add_header  X-Upstream  $upstream_addr;
    }
}

在 nginx 版本 1.7.5 之前,add_header 只能在请求成功时起作用,与HttpHeadersMoreModule不同。这是根据 Sebastian Goodman 的回答

自从 nginx 版本 1.7.5 版本以后,可以使用关键字 always 来包含自定义头部,即使是错误响应。例如:

add_header X-Upstream $upstream_addr always;

限制:您无法使用add_header覆盖server头的值。


54
自nginx 1.7.5版本以来,您可以使用"always"在错误响应中使用add_header包含自定义头部信息:add_header X-Upstream $upstream_addr always; - Shane
有没有一种类似的功能,而不需要暴露代理服务器的IP/端口组合?例如:X-Upstream: 10.10.10.10X-Upstream: 53c2d28edefdf501ab7c92e02a0c1687(md5可能无法掩盖基础设施,但它传达了这个想法)。 - zamnuts
@zamnuts: 传递上游IP和端口号只是使用“add_header”指令的一个例子。你不必发送它们。 - Oliver
@Oliver,我知道这一点,但我想询问除了IP/端口号之外的另一个个人/独特的上游标识符,或者是其混淆。也许我的问题超出了范围,我应该创建一个新的帖子 :) - zamnuts
@zamnuts:我建议您也提出一个新问题 :-) - Oliver
显示剩余3条评论

51

隐藏响应头并添加新的自定义头部值

使用 add_header 添加头部可以与代理传递一起正常工作,但如果响应中存在现有头部值,则会堆叠这些值。

如果您想设置或替换头部值(例如替换 Access-Control-Allow-Origin 头以匹配您的客户端以允许跨源资源共享),则可以按照以下方式进行:

# 1. hide the Access-Control-Allow-Origin from the server response
proxy_hide_header Access-Control-Allow-Origin;
# 2. add a new custom header that allows all * origins instead
add_header Access-Control-Allow-Origin *;

因此,proxy_hide_headeradd_header相结合,使您能够设置/替换响应头值。

类似的答案可以在这里的ServerFault上找到。

更新:

注意: proxy_set_header用于在请求进一步发送之前设置请求标头,而不是用于设置响应标头(这些标头的配置属性可能有点令人困惑)。


8
你关于 proxy_set_header 的评论帮助我理解了这两个调用之间的差异,谢谢 :) - JonnyRaa
1
add_header和proxy_hide_header的解释对我很有帮助。我一直在努力查看其中一个响应中的额外内容安全策略,这个解释帮助我理解了为什么会出现这种情况。 - ExpectoPatronum

41

正如Oliver所写:

add_headerproxy_pass一起使用也能正常工作。

但是,根据Shane的说法,在Nginx 1.7.5及以上版本中,如果想要让add_header在错误响应中生效,必须传递always参数,例如:

add_header  X-Upstream  $upstream_addr always;

6
我花了很长时间研究为什么我的标题没有显示,试图将它们移动到服务器块、位置块中……原来是因为nginx在错误响应中不会添加它们。谢谢! - Shautieh
1
我也是 :) 尽管如此,这种情况最近又发生在我身上了。不得不重新审查我的答案。 - Dmitry Minkovsky
请参阅http://nginx.org/en/docs/http/ngx_http_headers_module.html#add_header了解详细信息。 - Steve Eynon

37

有一个名为HttpHeadersMoreModule的模块,它可以让您更多地控制头信息。它不随Nginx一起提供,需要额外安装。使用它,您可以像这样做:

location ... {
  more_set_headers "Server: my_server";
}

这将“将服务器输出标头设置为任何状态代码和任何内容类型的自定义值”。它将替换已经设置的标头或在未设置的情况下添加它们。


能否在响应cookie上添加“Secure”和“HttpOnly”标志?目标响应cookie只有cookie“名称”和“过期”属性。 - JPaulPunzalan
2
你不一定需要使用库来更改或添加响应头,与得到最多赞的答案相反,你可以覆盖一个头部,只需先将其删除即可。请查看下面我的回答以获取详细信息。 - Wilt

17
你可以尝试这个解决方案:
在你的`location`块中,当你使用`proxy_pass`时,做以下操作:
location ... {

  add_header yourHeaderName yourValue;
  proxy_pass xxxx://xxx_my_proxy_addr_xxx;

  # Now use this solution:
  proxy_ignore_headers yourHeaderName // but set by proxy

  # Or if above didn't work maybe this:
  proxy_hide_header yourHeaderName // but set by proxy

}

我不确定这是否完全符合您的需求,但可以尝试对此方法进行一些操作,也许结果会适合您的问题。

您还可以尝试使用以下组合:

proxy_hide_header headerSetByProxy;
set $sent_http_header_set_by_proxy yourValue;

8
由于nginx添加了重复的标头而不是覆盖现有的标头,我不得不使用这种方法。location / { proxy_pass http://127.0.0.1:8080/; proxy_hide_header "Access-Control-Allow-Origin"; if ($http_origin ~* "^https://(example.com|www.example.com)$") { add_header Access-Control-Allow-Origin "$http_origin"; } } - ether6

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接