假设 nginx.conf 中有如下配置:
server {
listen 8080;
server_name 127.0.0.1;
...
# 请求后台接口的 api配置
location ^~ /userapi {
proxy_pass http://127.0.0.2:8081;
}
}
后台的一个接口的请求路径实际为:http://127.0.0.2:8081/userCenter/queryUserInfo,其中 /userCenter为后台接口服务工程的 server.servlet.context-path,
现在需要达到的效果就是浏览器输入 http://127.0.0.1:8080/userapi/queryUserInfo ,实际上需要 nginx 请求到 http://127.0.0.2/userCenter/queryUserInfo 接口,
但是现在对 nginx 的 location 的路径语法不熟悉,对 location --》proxy_pass 路径语法也不熟悉,不知道 userapi 前、后是否要带 " " 和 "/",不知道 http://127.0.0.2:8081 后面是否要带 "/" ( 还是带 /userCenter ),一个绝对正确的做法就是尝试全部的排列组合,location 的写法的全部可能性如下所示:
1. location ^~ /userapi{...
2. location ^~ /userapi {...
3. location ^~ /userapi/{...
4. location ^~ /userapi/ {...
5. location ^~ userapi{...
6. location ^~ userapi {...
7. location ^~ userapi/{...
8. location ^~ userapi/ {...
9. location ^~/userapi{...
10. location ^~/userapi {...
11. location ^~/userapi/{...
12. location ^~/userapi/ {...
13. location ^~userapi{...
14. location ^~userapi {...
15. location ^~userapi/{...
16. location ^~userapi/ {...
一共 16 种,
proxy_pass 的全部可能性如下所示:
1. http://127.0.0.2:8081;
2. http://127.0.0.2:8081/;
3. http://127.0.0.2:8081/userCenter;
4. http://127.0.0.2:8081/userCenter/;
一共 4 种,所以一共有 16 X 4 = 64 种可能性,像无头苍蝇一样试来试去,太费事费力,不可取。
如果可以将 nignx 最终拼成的向后台服务发出请求的完整 url 输出出来,则对我们定位是前缀拼错了还是后缀拼错了,或者多拼了什么还是少拼了什么有很大帮助....
方法是有的,可以查看 nginx 安装目录下的 access.log 和 error.log,例如:.../nginx-1.24.0/logs 下的 access.log、error.log,如果不想用此方法,或者nginx 加了什么配置导致不会输出,其实可以用第二种方案,在后台接口工程 userCenter 中加一个过滤器或者拦截器,比如拦截器如下所示:
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request1 = (HttpServletRequest) request;
String url = request1.getRequestURL().toString();
System.out.println( "url = " + url );
chain.doFilter(request, response);
}
这样所有的请求最终都会输出其完整的 url ,但是要记得将该工程的 server.servlet.context-path
临时修改为 "/",目的是使得即使 location 和 proxy_pass 的路径语法写错了,nginx 实际转发出去的地址也能被打到后台工程中,只是找不到对应的接口罢了( 当然 proxy_pass 必须以 "http://127.0.0.2:8081" 开头,你要是端口都写错了,那肯定不行 )。
以下是 2 种错误写法:
错误写法1:
发出请求:http://127.0.0.1:8080/userapi/queryUserInfo
location ^~ /userapi/ {
proxy_pass http://127.0.0.2:8081/;
}
实际的转发路径:http://127.0.0.2:8081/queryUserInfo
错误写法2:
发出请求:http://127.0.0.1:8080/userapi/queryUserInfo
location ^~ /userapi {
proxy_pass http://127.0.0.2:8081/;
}
实际的转发路径:http://127.0.0.2:8081//queryUserInfo
所以我们有理由相信 nginx 是将 proxy_pass 和 浏览器发出的 url 中去掉 location 中的部分后剩下的后缀部分 拼接在一起作为实际转发出去的 url,即 实际转发出去的 url = ${proxy_pass} + ${浏览器发出的地址}.replaceAll( ${location},"" )。这也就解释了为啥 "错误写法2" 中实际转发的路径中会有 "//" 了。
然后我们再测试2种正确写法和1种错误写法来更加应证明我们的猜想:
2种正确写法:
发出请求:http://127.0.0.1:8080/userapi/queryUserInfo
location ^~ /userapi/ {
proxy_pass http://127.0.0.2:8081/userCenter/;
}
实际转发出去的 url:http://127.0.0.2:8081/userCenter/queryUserInfo
发出请求:http://127.0.0.1:8080/userapi/queryUserInfo
location ^~ /userapi {
proxy_pass http://127.0.0.2:8081/userCenter;
}
实际转发出去的 url:http://127.0.0.2:8081/userCenter/queryUserInfo
1种错误写法:
发出请求:http://127.0.0.1:8080/userapi/queryUserInfo
location ^~ /userapi/ {
proxy_pass http://127.0.0.2:8081/userCenter;
}
实际转发出去的 url:http://127.0.0.2:8081/userCenterqueryUserInfo
最后记得还原后端工程的 server.servlet.context-path
结语:俗话说授人以鱼不如授人以渔,我们的脑子不应该装具体的正确的语法,应该装可以帮助我们快速找到正确的语法的方法,因为语法也是人写的嘛,是会变的,我不知道我也不care,只要知道解决问题的思路就行
ps:前端 vue、react 等脚手架工程本地启动设置后台接口代理如果配置不正确也可以使用此方法快速定位路径语法问题