问题场景:
项目中用到了多个子域名,测试环境通过子域名进行接口访问的时候返回 404 NOT_FOUND,经过排查测试后确定是 Nginx 配置问题,而导致事故的根本原因是运维在Nginx配置的时候少配置了一个斜杠(/),下面我们来聊聊具体情况。
故障现象如下:
nginx 配置如下:
location /api/{
client_max_body_size 100m;
proxy_connect_timeout 120;
proxy_send_timeout 120;
proxy_read_timeout 120;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header REMOTE-HOST $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://10.xxx.xxx.xxx:8080/api;
}
接口请求结果如下:
{
“code”: 404,
“message”: “404 NOT_FOUND”,
“data”: “”
}
问题分析:
- 接口不存在,直接通过服务部署的机器,通过 ip + 端口访问,正常响应。
- 网关 Gateway 有问题,通过 Gateway 服务部署的机器,通过 ip + 端口访问,正常响应。
- Nginx 配置有问题,通过 Nginx 的机器IP和暴露的端口去访问,响应 404,基本可以确定Nginx 配置有问题。
原因分析:
- 通过对问题现象分析,我们基本确定是 Nginx 配置的问题,我们取查询 Nginx 的日 看是否可以找到有效信息,没有找到有用信息。
- 接着我们对 Gateway 日志进行分析,看看是否可以找到有用的信息,我们发现了这样一段日志, /apidxx/v1/szzz/method(真实接口路径不方便暴露,请理解),apidxx 这段有明显问题,api 后面应该有个斜杆 / ,才接着是 dxx 才对,这段日志是在 Gateway 发现的,再次证明是 Nginx 配置的问题,现在我们进一步确定了是少了个斜杠 /,已经确定到了问题,现在去排查 Nginx 配置即可。
分析 Nginx 配置:
我们发现 proxy_pass http://10.xxx.xxx.xxx:8080/api 这段配置在api 后面没有接斜杠 / ,对比我们上面的分析,果断加上斜杠试试,重启后问题解决,正确的 Nginx 配置如下:
location /api/{
client_max_body_size 100m;
proxy_connect_timeout 120;
proxy_send_timeout 120;
proxy_read_timeout 120;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header REMOTE-HOST $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://10.xxx.xxx.xxx:8080/api/;
}
问题解决了,下面我们来分析一下,斜杠的各种场景。
location、proxy_pass 斜杠分析:
以下分析,不在赘述验证流程,感兴趣的朋友可以自己去验证,也欢迎提出疑问。
虚拟场景:我们需要通过 Nginx 代理访问地址:http://127.0.0.1/api/zt/app/list。
location加斜杠,proxy_pass 加api(上面分析的案例),如下:
location /api/ {
proxy_pass http://127.0.0.1:8888/api;
}
实际访问地址 :http://127.0.0.1:8888/apizt/app/list,这是个错误的地址,apizt 之间少了斜杠 /,导致 404。
location 不加斜杠,proxy_pass 加 api,api后面不加斜杠 /,如下:
location /api {
proxy_pass http://127.0.0.1:8888/api;
}
实际访问地址 :http://127.0.0.1:8888/api/zt/app/list,地址正确。
location 不加斜杠,proxy_pass 加 api,api后面加斜杠 /,如下:
location /api {
proxy_pass http://127.0.0.1:8888/api/;
}
实际访问地址 :http://127.0.0.1:8888/api/zt/app/list,地址正确。
location 加斜杠,proxy_pass 加 api,api后面加斜杠 /,如下:
location /api/ {
proxy_pass http://127.0.0.1:8888/api/;
}
实际访问地址 :http://127.0.0.1:8888/api/zt/app/list,地址正确。
location 不加斜杠,proxy_pass 不加 api,如下:
location /api {
proxy_pass http://127.0.0.1:8888;
}
实际访问地址 :http://127.0.0.1:8888/api/zt/app/list,地址正确。
location 加斜杠,proxy_pass 不加 api,如下:
location /api/ {
proxy_pass http://127.0.0.1:8888;
}
实际访问地址 :http://127.0.0.1:8888/api/zt/app/list,地址正确。
location 加斜杠,proxy_pass 不加 api,如下:
location /api {
proxy_pass http://127.0.0.1:8888/;
}
实际访问地址 :http://127.0.0.1:8888//api/zt/app/list,地址错误。
总结:
我们发现 proxy_pass 基本可以分为两种配置方法,一种是代理地址端口无字符,另外一种则是代理地址端口后有字符,下面给出结论:
- proxy_pass 代理地址端口后无任何字符,转发后实际地址:代理地址+访问URL接口路径部分。
- proxy_pass 代理地址端口后有目录(包括 / ),转发后实际地址:代理地址+访问URL目录部分去除location匹配目录。
Nginx常用命令:
#查看Nginx 进程命令
ps aux|grep nginx
#优雅停止Nginx服务器命令
/data/svr/nginx/sbin/nginx -s quit
启动Nginx服务器命令(Nginx 很多命令都是在 sbin 目录下执行)
去到sbin路径:cd /usr/local/nginx/sbin
启动Nginx服务器: ./nginx
#修改配置后检查配置文件是否出错
/data/svr/nginx/sbin/nginx -t
#修改配置后热加载
/data/svr/nginx/sbin/nginx -s reload
#指定启动配置文件命令
/data/svr/nginx/sbin/nginx -c /data/svr/nginx/conf/nginx.conf
#暴力停止Nginx服务器命令
/data/svr/nginx/sbin/nginx -s stop
#优雅停止Nginx服务器命令
/data/svr/nginx/sbin/nginx -s quit
如有不正确的地方欢迎各位指出纠正。