nginx系列(五)proxy_set_header设置
http://blog.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只认下划线,你要是搞成“-“就不生效了。
#通过这几个示例,将这个头信息传递的过程捋顺了,其他的配置里面出现的各种设置头信息什么的,基本也是可以理解的了。