nginx关于add_header的坑及解决

 更新时间:2023年12月22日 09:49:37   作者:Mr.zhang0325  
这篇文章主要介绍了nginx关于add_header的坑及解决,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教

一、add_header指令不会去重

nginx做反向代理时,如果后端返回的response中已经有该header头,则通过add_header后会返回给客户端两个同样的header头。

场景1:

nginxA作为反向代理,nginxB作为web服务。我是拿的openresty 1.13.6.2测试的,本质上是一样,其中A是openresty 1.15.8.1吗,B是openresty 1.13.6.2。

其中 nginxA 的日志格式里配置了打印上游返回的Server头: xes-app : $http_upstream_server

测试1:   add_header指令对重复指令的处理。

A的location配置如下:

server {
      listen 80;
      server_name test.header.com;
      access_log /home/nginx/logs/test.header.com_access.log main;
      error_log  /home/nginx/logs/error.log  debug;
 
      location / {
          set $upstream 'test.header.com';
          proxy_pass http://$upstream;
          proxy_set_header Host $host;
          proxy_set_header X-Real-IP $remote_addr;
          proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
          
      }
}

nginxB的配置如下:

server{
      listen 80;
      server_name test.header.com;
      access_log  /home/nginx/logs/test.header.com.log main;
      index  index.php index.html index.htm;
      location / {
            add_header Server 'MytestB'; 
            return 200 "this is test header from zlear"; 
      }       
}

这种配置下,B返回给A响应时会加上一个'Server: MytestB'的header。

  • 直接访问B:

  • 访问A,A反向代理到B:

此时只有一个Server的 header,而且是A的openresty 版本标识。

测试1结果:

1 : nginx返回响应时,会自动在http报文里加上了当前自己的Server标识。

2:  单纯的配置add_header指令时,如果response中已经有该header了,则会重复添加。

3:  通过反向代理NginxA之后,A会隐藏掉B返回给自己的Server Header头,并将自己的Server标识返回给客户端。

测试2: proxy_hide_headerproxy_pass_header指令对add_header有影响吗?

说明:proxy_hide_header : nginx在做反向代理时,为了隐藏上游服务器的信息,不会将上游的Server返回给客户端。

语法: proxy_hide_header field;

默认值: —

上下文: http, server, location

nginx默认不会将“Date”、“Server”、“X-Pad”,和“X-Accel-...”响应头发送给客户端。proxy_hide_header指令则可以设置额外的响应头,这些响应头也不会发送给客户端。

proxy_pass_header:   和proxy_hide_header相反,如果希望允许传递某些响应头给客户端,可以使用proxy_pass_header指令。

例如: proxy_pass_header Server; 则告诉nginx服务传递上游的Server头,而不是将它自己放在响应中。

  • 在测试1的基础上,在A上加上proxy_pass_header指令:
server {
      listen 80;
      server_name test.header.com;
      access_log /home/nginx/logs/test.header.com_access.log main;
      error_log  /home/nginx/logs/error.log  debug;
 
      location / {
          set $upstream 'test.header.com';
          proxy_pass http://$upstream;
          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_pass_header Server;
          
      }
}

通过A访问B如下:

此时和测试1中的直接访问B结果一样。

  • 在测试1的基础上,在NginxB上添加指令add_header MytestB MytestB;
server{
      listen 80;
      server_name test.header.com;
      access_log  /home/nginx/logs/test.header.com.log main;
      index  index.php index.html index.htm;
      location / {
            add_header Server  'MytestB'; 
            add_header MytestB 'MytestB'; 
            return 200 "this is test header from zlear"; 
      }       
}

测试2结果:

1、 nginx默认会隐藏上游返回的Server 的header头,但是可以通过pass_header_header Server;来取消该限制,此时用户会收到B返回的两个header头。

2、对于其他的非默认屏蔽的header头,则NginxA会原样透传给用户。如果想屏蔽某个header头,可以通过proxy_hide_header指令。

二、add_header指令会覆盖

如果在http、server、location都配置了add_header指令之后,返回给用户的是什么呢?

例如如下配置:

server {
      listen 80;
      server_name test.header.com;
      access_log /home/nginx/logs/test.header.com_access.log main;
      error_log  /home/nginx/logs/error.log  debug;
      add_header Test1 AAA;
 
      location / {
          set $upstream 'test.header.com';
          proxy_pass http://$upstream;
          proxy_set_header Host $host;
          proxy_set_header X-Real-IP $remote_addr;
          proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
          add_header Test2 BBB;
          
      }
}

这样的配置下,会返回给用户什么header呢?

答案是只会以location的为准,在server里配置的Test1并不生效。同理在http段配置的更加不会生效。 优先级location > server > http。

三、扩展

1、 ngx.resp.get_headers()

对Nginx A测试 ngx.resp.get_headers

-- header.lua
 
local json = require('cjson')
local h, err = ngx.resp.get_headers()
ngx.log(ngx.ERR, '-------resp header:-------', json.encode(h))

结果如下:

2020/08/06 10:07:02 [error] 5616#0: *15175 [lua] header.lua:9: -------resp header:-------{"connection":"keep-alive","content-type":"application\/octet-stream","mytestb":"MytestB","content-length":"34"} while reading response header from upstream, client: 127.0.0.1, server: test.header.com, request: "GET http://test.header.com/aaa HTTP/1.1", upstream: "http://xxxx:80/aaa", host: "test.header.com"

接着在A中加上配置项: proxy_pass_header Server;

再次测试结果:

2020/08/06 10:04:58 [error] 5564#0: *14655 [lua] header.lua:9: -------resp header:-------{"content-type":"application\/octet-stream","server":["openresty\/1.13.6.2","MytestB"],"connection":"keep-alive","mytestb":"MytestB","content-length":"34"} while reading response header from upstream, client: 127.0.0.1, server: test.header.com, request: "GET http://test.header.com/aaa HTTP/1.1", upstream: "http://xxx:80/aaa", host: "test.header.com"

结论

1、ngx.resp.get_headers() 只能获取到proxy_hide_header外的header头,如果想获取到默认被屏蔽掉的那些header,需要用proxy_pass_header来添加。

2、 默认情况下,此api获取到的header是一个key-value形式,但是如果upstream返回了两个同样的header,lua会用数组的形式存储。

2、 Server-tag会覆盖Server header头

后端B换成Tenginx,并且在nginx.conf中加上Server-tag: MytestB

则 B返回给A的响应头中,那个默认的Server头已经由openresty/1.13.6.1换成了 MytestB,则A再记录日志,返回给用户都是zzt-Server

3、  代码自定义Server的header头会覆盖nginx自带的

后端B是golang服务,golang代码里加上Server头,则同样可以满足2中的效果。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • 使用Nginx实现服务器中多容器共存的方法

    使用Nginx实现服务器中多容器共存的方法

    这篇文章主要介绍了使用Nginx实现服务器中多容器共存的方法,非常不错,具有一定的参考借鉴价值,需要的朋友可以参考下
    2018-10-10
  • 浅析nginx刚刚发布的JavaScript能力nginScript

    浅析nginx刚刚发布的JavaScript能力nginScript

    Nginx [engine x]是全球最受欢迎,也是最优秀的web服务器、反向代理服务器。nginScript是JavaScript/ECMAscript的子集,nginScript不是通过V8引擎实现的。本文给大家介绍nginx刚刚发布的JavaScript能力nginScript,感兴趣的朋友跟着小编一起了解了解吧
    2015-09-09
  • Nginx中防止SQL注入攻击的相关配置介绍

    Nginx中防止SQL注入攻击的相关配置介绍

    这篇文章主要介绍了Nginx中防止SQL注入攻击的相关配置介绍,文中提到的基本思路为将过滤的情况用rewrite重订向到404页面,需要的朋友可以参考下
    2016-01-01
  • windows下nginx如何操作命令

    windows下nginx如何操作命令

    这篇文章主要介绍了windows下nginx如何操作命令,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-06-06
  • nginx代理webSocket链接,webSocket频繁断开重连方式

    nginx代理webSocket链接,webSocket频繁断开重连方式

    当使用Nginx代理WebSocket连接时,若60秒内无数据交互,连接会断开,解决办法包括增加proxy_read_timeout时长或在客户端添加心跳机制,以维持连接稳定
    2024-09-09
  • nginx: [emerg] unknown directive报错误的问题

    nginx: [emerg] unknown directive报错误的问题

    本文主要介绍了nginx: [emerg] unknown directive报错误的问题,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2024-09-09
  • nginx多域名转发的实现

    nginx多域名转发的实现

    本文主要介绍了nginx多域名转发的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-03-03
  • Nginx的信号控制

    Nginx的信号控制

    今天小编就为大家分享一篇关于Nginx的信号控制,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2018-10-10
  • Nginx服务器上搭建图片缓存服务的基本配置解析

    Nginx服务器上搭建图片缓存服务的基本配置解析

    这篇文章主要介绍了Nginx服务器上搭建图片缓存服务的基本配置解析,分别介绍了通过proxy_store模块和proxy_cache模块两种方式的配置,需要的朋友可以参考下
    2016-04-04
  • Nginx location(正则)使用

    Nginx location(正则)使用

    这篇文章主要介绍了Nginx location(正则)使用,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-06-06

最新评论