柴少鹏的官方网站 技术在分享中进步,水平在学习中升华

nginx系列(五)proxy_set_header设置

http://www.51niux.com/?id=126  #已经对HTTP的header头信息做了简单介绍。

一、proxy_set_header介绍

1.1 先来了解下HTTP的请求方式($request_method)

GET:向Web服务器请求一个文件
POST:向Web服务器发送数据让Web服务器进行处理
PUT:向Web服务器发送数据并存储在Web服务器内部
HEAD:检查一个对象是否存在
DELETE:从Web服务器上删除一个文件
CONNECT:对通道提供支持
TRACE:跟踪到服务器的路径
OPTIONS:查询Web服务器的性能

#这个很有用的,我们可以根据请求的方式做出不同的判断操作在nginx配置文件里面。

1.2 再来了解下proxy_set_header语法

语法:    proxy_set_header field value;
默认值:    
proxy_set_header Host $proxy_host;
proxy_set_header Connection close;
上下文:    http, server, location

允许重新定义或者添加发往后端服务器的请求头。value可以包含文本、变量或者它们的组合。 当且仅当当前配置级别中没有定义proxy_set_header指令时,会从上面的级别继承配置。 默认情况下,只有两个请求头会被重新定义:

proxy_set_header Host       $proxy_host;
proxy_set_header Connection close;

二、示例记录proxy_set_header的使用方法

现在我是192.168.1.103作为最前端的nginx代理服务器,然后将请求发送给(这种三级架构再稍微大一点的公司是很常见的)

 upstream backend_image {
               server 192.168.1.107:80;
               server 192.168.1.108:80;
               keepalive 32;
     }

然后192.168.1.107和192.168.108还是一层代理又代理了后端的一组服务器

 upstream backend_image {
               server 192.168.1.104:80;
               server 192.168.1.105:80;
               keepalive 32;
     }

博文来自:www.51niux.com

2.1 示例一(向后端传输一个我们自定义的参数)

首先先来看下如果不设置的效果:

统一的日志格式为:

 log_format  main   '$remote_addr - $remote_user [$time_local] "$request"'
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" $http_x_forwarded_for "$Host"';

访问一个链接:http://test1.51niux.com/test1/10.jpg   #查看这三层结构的日志输出

192.168.1.103上面的日志输出:

192.168.1.114 - - [29/Jun/2017:18:41:37 +0800] "GET /test1/10.jpg HTTP/1.1"404 169 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:54.0) Gecko/20100101 Firefox/54.0" - "test1.51niux.com"

192.168.1.108上面的日志输出:

192.168.1.103 - - [29/Jun/2017:18:42:01 +0800] "GET /images/test1/10.jpg HTTP/1.0" 404 169 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:54.0) Gecko/20100101 Firefox/54.0" "-" "backend_image"

192.168.1.104上面的日志输出:

192.168.1.108 - - [29/Jun/2017:18:41:37 +0800] "GET /images/test1/10.jpg HTTP/1.0" 404 169 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:54.0) Gecko/20100101 Firefox/54.0" "-" "backend_image_backend"

#从上面的结果来推断一下,最前面的nginx的$remote_addr(客户端IP)获取的是真实的客户IP地址,而后面两层nginx后端服务器获取的都是自己上一层nginx的IP。然后$host(用户访问的主机或域名)也是如此。

那么下面我们稍微在最前端修改一下:

   location @not_found {
                  rewrite    /(.*)  /images/$1 break;
                  proxy_set_header    Host    $host;  #我们把$host头的值传给了Host
                  proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;  #将$proxy_add_x_forwarded_for传递给了X-Forwarded-For
                  proxy_store /data/proxy_store/51niux_images/$1;
                  proxy_pass http://backend_image;
           }

再来访问一个链接:http://test1.51niux.com/test1/10.jpg   #查看这三层结构的日志输出

192.168.1.103上面的日志输出:

192.168.1.114 - - [29/Jun/2017:18:56:22 +0800] "GET /test1/10.jpg HTTP/1.1"404 8 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:54.0) Gecko/20100101 Firefox/54.0" - "test1.51niux.com"

192.168.1.107上面的日志输出:

192.168.1.103 - - [29/Jun/2017:18:56:48 +0800] "GET /images/test1/10.jpg HTTP/1.0" 404 8 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:54.0) Gecko/20100101 Firefox/54.0" "192.168.1.114" "test1.51niux.com"

192.168.1.105上面的日志输出:

192.168.1.107 - - [29/Jun/2017:18:57:45 +0800] "GET /images/test1/10.jpg HTTP/1.0" 404 8 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:54.0) Gecko/20100101 Firefox/54.0" "192.168.1.114" "backend_image_backend"

#从上面的结果来推断一下,首先Host的值从192.168.1.103只传递到了192.168.1.107,但是下一层就失效了,192.168.1.107传递给192.168.1.103的又失效了还是原来的格式。但是$http_x_forwarded_for这个后端两个nginx的值却是统一的。proxy_add_x_forwarded_for这个下一个示例再说是咋回事。然后你看192.168.1.103的$http_x_forwarded_for输出的是-,表示什么都没有。是不是似乎知道咋回事了。

那么我们再做一些稍微的调整来验证一下:

日志格式统一为:

log_format  main   '$remote_addr - $remote_user [$time_local] "$request"'
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" $http_x_forwarded_for "$Host" "$http_Test1"';

192.168.1.103上面的设置:

proxy_set_header    Host    $host;
proxy_set_header    Test1   $host;  #我们又新加了一个要传递给后端的头Test1,并且把$host的值传递给Test1

192.168.1.107和192.168.1.108上面的设置:

  location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$ {
             proxy_pass http://backend_image_backend;
             proxy_set_header    Host    $host;  #我们再次把$host头的值传递给后端服务器
        }

再来访问一个链接:http://test1.51niux.com/test1/10.jpg   #查看这三层结构的日志输出:

192.168.1.103上面的日志输出:

192.168.1.114 - - [29/Jun/2017:19:27:37 +0800] "GET /test1/10.jpg HTTP/1.1"404 169 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:54.0) Gecko/20100101 Firefox/54.0" - "test1.51niux.com" "-"

192.168.1.107上面的日志输出:

192.168.1.103 - - [29/Jun/2017:19:28:02 +0800] "GET /images/test1/10.jpg HTTP/1.0" 404 8 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:54.0) Gecko/20100101 Firefox/54.0" "192.168.1.114" "test1.51niux.com" "test1.51niux.com"

192.168.1.104上面的日志输出:

192.168.1.108 - - [29/Jun/2017:19:27:37 +0800] "GET /images/test1/10.jpg HTTP/1.0" 404 169 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:54.0) Gecko/20100101 Firefox/54.0" "192.168.1.114" "test1.51niux.com" "test1.51niux.com"

2.2 对示例1的结论

结论1:

proxy_set_header :就负责定义一下自定义的header变量和值传递给后端,让后端接收,自己本身除了nginx默认的那些header,获取不了这些自定义的header头的内容。

结论2:

如果是nginx默认的那些header,proxy_set_header的作用范围只是一层,也就是只能辐射到自己后端的服务器,例如$host这个值,如果还像继续向下传递,就需要自己后端的服务器也设置一下,这样才能让值继续向下辐射。

结论3:

如果是nginx不带的那些header,也就是我们自定义无中生有的,例如Test1这些,是可以一直向下辐射的,因为nginx自身没有这些header,所以下一次nginx也不会用自己的header去覆盖。

结论4:

通过proxy_set_header设置的header,在log_format那里是不区分大小写的。当然为了统一规范,就一律采用小写吧。

结论5:

如果通过proxy_set_header设置的header,不是nginx默认的那些header,就要在其头加上http_标识,不然启动nginx是会报错的。如:Test1跑到log_format里面就变成了$http_test1。

2.3 示例3(开启header的下划线支持)

proxy_set_header    Test1_Test1   $host;

现在后端的日志格式改为:

log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for" "$Host" "$http_test1_test1"';

#如果我们发现有些自定义的header想设置成带有下划线的标签,如果不在后端的nginx服务器里面加上一个参数的话,会是下面的结果:

192.168.1.103 - - [29/Jun/2017:19:42:53 +0800] "GET /images/test1/10.jpg HTTP/1.0" 404 169 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:54.0) Gecko/20100101 Firefox/54.0" "192.168.1.114" "test1.51niux.com" "-"

然后再后端的nginx的http或者server标签下面加上下面的参数:

underscores_in_headers on;   #这个参数默认是关闭的。这个参数的作用就是是否允许在header的字段中带下划线。

然后再次查看后端的日志输出:

192.168.1.108的日志输出:

192.168.1.103 - - [29/Jun/2017:19:42:52 +0800] "GET /images/test1/10.jpg HTTP/1.0" 404 169 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:54.0) Gecko/20100101 Firefox/54.0" "192.168.1.114" "test1.51niux.com" "test1.51niux.com"

博文来自:www.51niux.com

2.4 示例4(proxy_add_x_forwarded_for的再具体介绍)

首先了解下什么是X-Forwarded-For变量:

X-Forwarded-For变量,这是一个squid开发的,用于识别通过HTTP代理或负载平衡器原始IP一个连接到Web服务器的客户机地址的非rfc标准,如果有做X-Forwarded-For设置的话,每次经过proxy转发都会有记录,格式就是client1, proxy1, proxy2,以逗号隔开各个地址,由于他是非rfc标准,所以默认是没有的,需要强制添加,在默认情况下经过proxy转发的请求,在后端看来远程地址都是proxy端的ip 。

了解$proxy_add_x_forwarded_for的意思:

proxy_set_header            X-Forwarded-For $proxy_add_x_forwarded_for;  #意思是增加一个$proxy_add_x_forwarded_for到X-Forwarded-For里去,注意是增加,而不是覆盖,当然由于默认的X-Forwarded-For值是空的,所以我们总感觉X-Forwarded-For的值就等于$proxy_add_x_forwarded_for的值。

示例演示:

下面在192.168.1.107和192.168.1.108上面做操作:

location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$ {
             proxy_pass http://backend_image_backend;
              proxy_set_header    Host    $host;
             proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;  #也设置这一条
        }

再来访问一个链接:http://test1.51niux.com/test1/10.jpg   #查看这三层结构的日志输出:

192.168.1.103的日志输出:

192.168.1.114 - - [29/Jun/2017:19:58:16 +0800] "GET /test1/10.jpg HTTP/1.1"404 169 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:54.0) Gecko/20100101 Firefox/54.0" - "test1.51niux.com" "-"

192.168.1.108的日志输出:

192.168.1.103 - - [29/Jun/2017:19:58:41 +0800] "GET /images/test1/10.jpg HTTP/1.0" 404 169 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:54.0) Gecko/20100101 Firefox/54.0" "192.168.1.114" "test1.51niux.com" "test1.51niux.com"

192.168.1.104的日志输出:

192.168.1.108 - - [29/Jun/2017:19:58:16 +0800] "GET /images/test1/10.jpg HTTP/1.0" 404 169 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:54.0) Gecko/20100101 Firefox/54.0" "192.168.1.114, 192.168.1.103" "test1.51niux.com" "-"

#从结果上面看,192.168.1.103作为第一层nginx肯定没啥反应了,然后192.168.1.108做了第二层nginxX-Forwarded-For里面还是一个值(192.168.1.103传给他的值),然后192.168.1.104作为第三层nginx日志输出发生了很大的变化,X-Forwarded-For的值变成了“192.168.1.114,192.168.1.103”,也就是说192.168.1.108也增加了一个值进去,也就是192.168.1.108上一层nginx的ip(对于192.168.1.108来说192.168.1.103就是它的客户端)。

2.5 示例5(X-Real-IP说明)

 proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;
 proxy_set_header   X-Real-IP        $remote_addr;

#上面两个参数是经常出现在nginx反向代理中的,上面一条已经介绍了,其实下面一条X-Real-IP就跟示例4中提到的Test1_Test1是一个意思,都是搞一个不存在的header,然后nginx把获取到的header信息赋值给这个变量。

#所以很多人说X-Real-IP可以在多层负载均衡中将最开始的开源IP传递给后端,因为nginx里面就没有X-Real-IP这个预定义的东西,所以往下传没人去覆盖它,它的值不会变,就一直传下去了。就是示例4中的意思。

#另外就是log_format的格式。

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for" "$Host" "$http_Test1_Test1" "$http_x_real_ip"';

#从上图中可以看出不管是X-Forwarded-For还是X-Real-IP,到了log_format中都从中间横线变成了下划线,因为log_farmat只认下划线,你要是搞成“-“就不生效了。

#通过这几个示例,将这个头信息传递的过程捋顺了,其他的配置里面出现的各种设置头信息什么的,基本也是可以理解的了。

作者:忙碌的柴少 分类:Web环境搭建 浏览:4842 评论:0
留言列表
发表评论
来宾的头像