1. 博客/

Nginx请求头proxy_set_header

·229 字·2 分钟
Nginx

前言
#

nginx作为反向代理时,当满足location匹配条件后,向后端动态应用服务器发送请求,如果后端服务器会根据此次请求头做一些操作(比如通过Host或者server_name请求头的值进行校验等),就会出现问题。本文就用实例来分析一下nginx转发的请求头信息

环境准备
#

IPSERVER
10.168.11.12Nginx1.12
10.168.11.13Tomcat7.0

一、准备tomcat war包

  1. 创建test.jsp文件来获取各请求头信息
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
<%
out.println("Protocol: " + request.getProtocol());  
out.println("Server Name: " + request.getServerName());  
out.println("Server Port: " + request.getServerPort());  
out.println("Remote Addr: " + request.getRemoteAddr());  
out.println("Remote Host: " + request.getRemoteHost());  
out.println("Request URL: " + request.getRequestURL());  
out.println("Host: " + request.getHeader("Host"));  
out.println("Connection : " + request.getHeader("Connection"));  
%>
  1. 打包th.war并部署
jar cvf th.war th/test.jsp

10.168.11.13服务器上安装Tomcat7.0,并监听30000端口。这里不再描述tomcat安装部署及发布包的步骤。

  1. 访问http://10.168.11.13:30000/th/test.jsp

tomcat从请求中获取的信息如下:

Protocol: HTTP/1.1                                                      <-- http协议版本
Server Name: 10.168.11.13
Server Port: 30000
Remote Addr: 10.168.196.134                                             <-- client IP
Remote Host: 10.168.196.134                                             <-- client IP
Request URL: http://10.168.11.13:30000/th/test.jsp
Host: 10.168.11.13:30000
Connection : keep-alive

二、配置Nginx

  1. nginx.conf中定义server、upstream
upstream backendsrv {
    server 10.168.11.13:30000;
}
server {
    listen       10000;
    server_name  www.test.com;
    location /th {
        root   html;
        index  index.html index.htm;
        proxy_pass http://backendsrv;
     }
}
  1. 启动nginx并访问http://10.168.11.12:10000/th/test.jsp
Protocol: HTTP/1.0
Server Name: backendsrv
Server Port: 80
Remote Addr: 10.168.11.12
Remote Host: 10.168.11.12
Request URL: http://backendsrv/th/test.jsp
Host: backendsrv
Connection : close
  1. Nginx代理发送http请求默认为HTTP 1.0,可通过定义proxy_http_version 1.1来修改,一般是在使用keepalive连接时才使用1.1版本
  2. 在使用proxy_set_header的默认值时,Nginx发往后端请求中的Host及server_name为代理的upstream中指定的域名

结果分析
#

1.以下是官方doc中的描述 Syntax: proxy_set_header field value; Default: ​ proxy_set_header Host $proxy_host; ​ proxy_set_header Connection close; Context: http, server, location

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

所以当客户端访问未携带Host请求头部,并使用proxy_set_header默认值时,请求头部Host值为backendsrv,Connection值为close,而端口则为默认80

2.$host 和 $http_host的区别

在server上下文中分别指定请求头Host值为$host和$http_host,结果对比如下:

proxy_set_header Host $hostproxy_set_header Host $http_host
ProtocolHTTP/1.0HTTP/1.0
Server Namewww.test.comwww.test.com
Server Port8010000
Remote Addr10.168.11.1210.168.11.12
Remote Host10.168.11.1210.168.11.12
Request URLhttp://www.test.com/th/test.jsphttp://www.test.com:10000/th/test.jsp
Hostwww.test.comwww.test.com:10000
Connectioncloseclose

可以看出,由于客户端访问未携带Host请求头部,无法继承,则被修改为server上下文中定义的虚拟主机名www.test.com;并且$http_host会修改默认端口80为server上下文中监听的端口10000。所以当后端应用服务器需要根据请求头部Host信息做进一步处理时,要根据需求在nginx中正确配置Host值。

最佳实践
#

当后端服务器有301、302跳转时,需要注意指定proxy_set_header Host请求头部,会直接影响nginx反馈给客户端的URL请求,要结合实际需求调整proxy_set_header Host和proxy_redirect将被代理服务器设置在response header中的Location做转换。

Related

P2P文件与镜像分发开源解决方案Dragonfly安装部署
·859 字·5 分钟
Docker