场景
网络访问关系图如下, PC浏览器需要访问到Tomcat的Web应用.
因为网络隔离, PC机所在的环境访问不了Nginx2, 所以加了一层Nginx1的网络代理. Ngnix1的简要配置如下:
server{
listen 8888;
server_name 10.254.209.65;
location / {
proxy_pass http://10.254.213.149:80;
}
}
然后Nginx2代理了tomcat应用, 简要配置如下:
upstream tom {
server ip:port;
}
server {
listen 80;
server_name 10.254.213.149;
location /admin {
proxy_pass http://tom/admin;
}
}
问题
在PC浏览器上输入10.254.209.65:8888/admin/就可以正常显示tomcat的web页面, 而输入10.254.209.65:8888/admin 时就404, 后者比前者少了一个斜杠“/”而已.
排查
在PC浏览器输入10.254.209.65:8888/admin 时, 发现地址会莫名其妙地重定向为 10.254.209.65/admin/
重定向之后的地址有2处明显变化: 一是端口8888变成了80(默认不显示) ; 二是admin后面追加上了斜杠“/”.
似乎问题的根源还是斜杠“/”, 那就先从它入手.
Nginx不会自动追加斜杠“/”, 其配置文件里也没有显示去追加“/”, 于是开始怀疑到Tomcat.
切到Nginx2所在主机下, 不走代理, 通过curl直接访问Tomcat应用:
curl -I http://tom/admin
显示信息如下
HTTP/1.1 302
Location: http://tom/admin/Transfer-Encoding: chunked
Date: Sun, 30 Dec 2018 13:24:35 GMT
确实发生了302重定向, 并且地址追加上了斜杠“/”.
想了想应用代码应该不会无故干这种事, 难道是Tomcat自己干的?
于是去看了一下Tomcat的access日志, 确实有一个302. 然后去网上查了一下资料, 大致就是说当Tomcat的应用带有contentPath的时候, 比如这里的/admin, 那么客户端访问时, 如果直接请求/admin的话, Tomcat就会自动重定向去追加斜杠变成/admin/.
到此, 我们似乎已经知道如何去解决问题了, 只要在Nginx2的proxy_pass地址后面显示加个“/”就行了, 如下:
proxy_pass http://tom/admin/;
这样/admin请求在Nginx2处转发时就会带上“/”, 然后Tomcat收到请求后就不会再重定向了.
验证一下, 在PC上输入10.254.209.65:8888/admin 确实访问正常了.
看似问题是解决了, 但是重定向端口号从8888变成了80还没有查明, 里面一定有坑.
重定向不同于服务器内部转发, 重定向的指令是服务器发给客户端的, 当然应该使用客户端输入的IP和PORT.
继续分析, 这时产生了一个错觉: Tomcat在重定时拿到的端口号不对, 它只拿到了最近一个Nginx的端口, 即Nginx2的端口80, 而拿不到Nginx1的8888.
为什么说是错觉呢, 因为Tomcat其实根本不会去拿什么端口号,它只会拿当前Http请求的Head里面的Host信息.
为什么用Nginx这么久, 很少碰到这种端口问题, 因为一般用的端口是80, 而Nginx代理时Host的取值默认是$host, 相当于$host:80, 所以也就不会出问题.
在一些特殊场景出现非80端口时, 如果只有一层Nginx代理还好说, 可以在代理时设置Head转发后的Host值, 把端口带上, 如下
proxy_set_header Host $host:$server_port;
但是对于当前问题场景, 有2层Nginx代理, Nginx2无法直接拿到Nginx1的端口信息, 那怎么办呢?
目前能想到的方法, 就是在代理/admin下设置Host时, 把配置端口写死, 如下:
proxy_set_header Host $host:8888;
这样当Tomcat重定向时就没有问题了, 不过你得先知道客户端请求的端口是8888, 当其变化后也需要跟着同步.
来源:oschina
链接:https://my.oschina.net/u/735642/blog/2995664