在配置nginx反向代理时,location和proxy_pass后面加不加/,很多人都不会去注意这个细节,实际上加不加区别还是很大的,下面就举个具体的例子来说明。
一些准备工作
tomcat
首先准备一个tomcat,在webapps里放置两个项目demo1和demo2,项目里面创建一个test.jsp,内容如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%
String remoteAddr = request.getRemoteAddr();
String forwarded = request.getHeader("X-Forwarded-For");
String realIp = request.getHeader("X-Real-IP");
int port = request.getServerPort();
StringBuffer requestURL = request.getRequestURL();
%>
ip=<%=remoteAddr%>
<br/>
X-Forwarded-For=<%=forwarded%>
<br/>
X-Real-IP=<%=realIp%>
<br/>
port=<%=port%>
<br/>
requestURL = <%=requestURL%>
<br/>
<img src="tomcat.png" alt="tomcat" />
<br/>
当前访问文件路径:demo1/test.jsp
</body>
</html>
demo2里的也一样建立test.jsp,内容一样,除了最后文件路径不同
另外在ROOT文件夹下建立三个文件,分别是test.jsp,demo1test.jsp和demo2test.jsp,用途后面讲,内容跟上面一样
nginx
接着准备一个nginx,虚拟主机配置如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56server {
listen 8081;
server_name 192.168.44.153;
location /demo1/ {
proxy_pass http://127.0.0.1:8080/;
}
}
server {
listen 8082;
server_name 192.168.44.153;
location /demo1/ {
proxy_pass http://127.0.0.1:8080;
}
}
server {
listen 8083;
server_name 192.168.44.153;
location /demo1/ {
proxy_pass http://127.0.0.1:8080/demo2/;
}
}
server {
listen 8084;
server_name 192.168.44.153;
location /demo1/ {
proxy_pass http://127.0.0.1:8080/demo2;
}
}
server {
listen 8085;
server_name 192.168.44.153;
location /demo1 {
proxy_pass http://127.0.0.1:8080/;
}
}
server {
listen 8086;
server_name 192.168.44.153;
location /demo1 {
proxy_pass http://127.0.0.1:8080;
}
}
server {
listen 8087;
server_name 192.168.44.153;
location /demo1 {
proxy_pass http://127.0.0.1:8080/demo2/;
}
}
server {
listen 8088;
server_name 192.168.44.153;
location /demo1 {
proxy_pass http://127.0.0.1:8080/demo2;
}
}
proxy_pass后面/
首先我们先验证proxy_pass后面加不加/的影响
1、proxy_pass根目录后面加/
1 | location /demo1/ { |
访问http://192.168.44.153:8081/demo1/test.jsp 结果如下:
2、proxy_pass根目录后面不加/
1 | location /demo1/ { |
访问http://192.168.44.153:8082/demo1/test.jsp 结果如下:
3、proxy_pass项目名后加/
1 | location /demo1/ { |
访问http://192.168.44.153:8083/demo1/test.jsp 结果如下:
4、proxy_pass项目名后不加/
1 | location /demo1/ { |
访问http://192.168.44.153:8084/demo1/test.jsp 结果如下:
location后面/
接着我们先验证location后面加不加/的影响
5、proxy_pass根目录后面加/
1 | location /demo1 { |
访问http://192.168.44.153:8085/demo1/test.jsp 结果如下:
6、proxy_pass根目录后面不加/
1 | location /demo1 { |
访问http://192.168.44.153:8086/demo1/test.jsp 结果如下:
7、proxy_pass项目名后加/
1 | location /demo1 { |
访问http://192.168.44.153:8087/demo1/test.jsp 结果如下:
8、proxy_pass项目名后不加/
1 | location /demo1 { |
访问http://192.168.44.153:8088/demo1/test.jsp 结果如下:
其他一些细节
写到这里可能就有人要问了,X-Forwarded-For和X-Real-IP是什么鬼?我们注意看下上面的截图,会发现后端使用request.getRequestURL()得到的地址都是错误的,这个是因为经过nginx代理后,用getRequestURL()得到的地址其实是nginx里配置的proxy_pass地址,所以如果想要得到正确的地址,需要对nginx追加参数,具体配置如下:1
2
3
4
5
6
7
8
9
10server {
listen 8082;
server_name 192.168.44.153;
location /demo1/ {
proxy_set_header Host $host:$server_port;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://127.0.0.1:8080;
}
}
结果如下:
这边主要是第一句proxy_set_header Host $host:$server_port;
起的作用,意思是重新定义发往后端的Host请求头,而$host和$server_port是nginx默认的两个变量。通过这句可以使后端得到的ip和端口正确。
而后面两句其实是为了得到客户端真实ip和经过几个代理节点的。
例如我这边在172.16.39.11上在部署一台nginx,转向本地(192.168.44.153)1
2
3
4
5
6
7
8
9
10server {
listen 8082;
server_name 192.168.44.153;
location /demo1/ {
proxy_set_header Host $host:$server_port;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://192.168.44.153:8082/demo1/;
}
}
此时访问http://172.16.39.11:8082/demo1/test.jsp 可以得到如下结果:
可以看出X-Real-IP是最后一个节点ip,而X-Forwarded-For是该请求经过了几个节点的集合,如果要让X-Real-IP指向客户端真实ip,可以在除第一台nginx外的其他nginx上把proxy_set_header X-Real-IP $remote_addr;改成proxy_set_header X-Real-IP $http_x_real_ip; 即可变成客户端真实ip。
另外,这边的request.getRemoteAddr()配置nginx后至始至终都是错误的,说明后端在写代码的时候,尽量少用这个函数获取,最好是自己封装一个方法,先从X-Forwarded-For或X-Real-IP取,取不到了再从getRemoteAddr()中取。
参考资料:
实战Nginx:取代Apache的高性能Web服务器 张宴
精通Nginx(第2版)
下载地址:
链接: https://pan.baidu.com/s/1h4qYIWe6NV4YfPVrOwsKeg 提取码: pxym