- 博客/
Nginx的proxy_redirect配置
前言#
当nginx代理的后端服务器有301、302跳转时,需要注意指定proxy_set_header Host请求头部,会直接影响nginx反馈给客户端的URL请求,要结合实际需求调整proxy_set_header Host和proxy_redirect将被代理服务器设置在response header中的Location做转换。
搭建测试环境#
1.测试架构规划
- 主机192.168.196.134
- nginx虚拟主机www.test.com;监听端口31001;转发文根 /th;后端server 192.168.196.135:31009
- nginx虚拟主机192.168.196.134;监听端口31000;转发文根 *.jsp;后端server 192.168.196.136:31005
- 主机192.168.196.135
- nginx虚拟主机 192.168.196.135;监听端口31009;转发文根 /th/ft;后端server 192.168.196.134:31000
- 主机192.168.196.136
- tomcat server; 监听端口31005
192.168.196.134:31001/th —> 192.168.196.135:31009/th/ft –> 192.168.196.134:31000 *.jsp –> 192.168.196.136:31005
2.192.168.196.136上部署war包
sh-4.2$ cat 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"));
%>
$jar cvf th.war th/ft/test.jsp
3.192.168.196.134上配置 nginx
upstream backendsrv {
server 192.168.196.136:31005;
}
server {
listen 31001;
server_name www.test.com;
location /th {
root html;
index index.html index.htm;
proxy_pass http://192.168.196.135:31009;
#proxy_redirect ~^http://www.test.com:31009(.*) http://$host:$server_port$1;
proxy_set_header Host $http_host;
}
}
server {
listen 31000;
server_name www.firsthost.com 192.168.196.134;
location /th/ft {
root html;
index index.html index.htm;
}
location ~* .jsp$ {
proxy_pass http://backendsrv;
proxy_set_header Host $http_host;
}
}
4.192.168.196.135上配置nginx
upstream backendnginx {
server 192.168.196.134:31000;
}
server {
listen 31009;
server_name 192.168.196.135;
location /th/ft {
root html;
index index.html index.htm;
proxy_pass http://backendnginx;
#proxy_redirect ~^http://www.test.com:31000(.*) http://$host:$server_port$1;
proxy_set_header Host $http_host;
}
location /th {
root html;
index index.html index.htm;
}
}
5.按照当前配置在客户端访问:
$curl -L www.test.com:31001/th/ft/test.jsp
Protocol: HTTP/1.0
Server Name: www.test.com
Server Port: 31001
Remote Addr: 192.168.196.134
Remote Host: 192.168.196.134
Request URL: http://www.test.com:31001/th/ft/test.jsp
Host: www.test.com:31001
Connection : close
由于每个转发文根下都设置了Host请求头(proxy_set_header Host $http_host;),最终tomcat应用服务器从请求中获取的Host信息为面向客户端的第一级代理nginx的虚拟主机server_name及监听端口
$curl -I www.test.com:31001/th
HTTP/1.1 301 Moved Permanently
Server: nginx
Date: Thu, 21 Mar 2019 02:50:47 GMT
Content-Type: text/html
Content-Length: 178
Connection: keep-alive
Location: http://www.test.com:31009/th/
$curl -I www.test.com:31001/th/ft
HTTP/1.1 301 Moved Permanently
Server: nginx
Date: Thu, 21 Mar 2019 02:50:51 GMT
Content-Type: text/html
Content-Length: 178
Connection: keep-alive
Location: http://www.test.com:31000/th/ft/
301跳转时,返回给客户端重新发送请求的Location中URL有问题。 后端server的响应头中的location字段信息为: 1.host值被设置为第一个转发Location所在虚拟主机的server_name www.test.com
这里要注意的时,如果nginx转发Location中未设置Host请求头,则host值为proxy_pass后指定的地址
2.端口被设置为每个转发Location中proxy_pass/upstream定义的端口
此时要用proxy_redirect将被代理服务器设置在response header中的Location做转换。官方解释:
proxy_redirect 语法:proxy_redirect [ default|off|redirect replacement ] 默认值:proxy_redirect default 使用字段:http, server, location 如果需要修改从被代理服务器传来的应答头中的"Location"和"Refresh"字段,可以用这个指令设置。
6.根据上面的访问结果,对应跳转地址:/th –> /th/和/th/ft –> /th/ft/
在相应的转发Location下,分别添加:
- proxy_redirect ~^http://www.test.com:31009(.*)
http://$host:$server_port$1;
- proxy_redirect ~^http://www.test.com:31000(.*)
http://$host:$server_port$1;
$host
和$server_port
分别为转发文根Location所在虚拟主机的server_name和listen port
7.reload Nginx后,从客户端访问
$curl -I www.test.com:31001/th
HTTP/1.1 301 Moved Permanently
Server: nginx
Date: Thu, 21 Mar 2019 03:15:10 GMT
Content-Type: text/html
Content-Length: 178
Connection: keep-alive
Location: http://www.test.com:31001/th/
$curl -I www.test.com:31001/th/ft
HTTP/1.1 301 Moved Permanently
Server: nginx
Date: Thu, 21 Mar 2019 03:18:22 GMT
Content-Type: text/html
Content-Length: 178
Connection: keep-alive
Location: http://www.test.com:31001/th/ft
301跳转时,返回给客户端重新发送请求的Location中URL已正确显示
最佳实践#
依据转发Location中Host请求头是否被指定,来修改proxy_redirect的值:
如果Host请求头未指定过,则后端server返回的Location为nginx中
proxy_pass后的servername/IP
与proxy_pass后的端口或upstream中转发端口
的拼接如果Host请求头在当前转发Location指定
- Host在nginx收到的请求中未指定过,则后端server返回的Location为
nginx当前转发Location的server_name
与proxy_pass后的端口或upstream中转发端口
的拼接 - Host在nginx收到的请求中已指定,则后端server返回的Location为
nginx接收的请求中Host
与proxy_pass后的端口或upstream中转发端口
的拼接
- Host在nginx收到的请求中未指定过,则后端server返回的Location为