现象
开发人员反馈,测试环境某个接口全是返回400,具体开始出现的时间未知了,但目前全是400
接口情况
浏览器--->Nginx--> Java 进程
排查过程
- 检查nginx配置
都是最简单的负载均衡配置,看不出有啥异常
upstream server_single {
server 192.167.1.125:8070;
server 192.167.1.126:8070;
}
......
location /server_single/{
proxy_pass http://server_single/;
}
- 从nginx服务器上分别对负载均衡接口和服务器真实地址curl
- 发现使用 http://localhost:9090/server_single/xxx 访问,总是404
- 使用 http://192.167.1.125:8070/xxx 就能得到正常结果
- 在java 进程所在服务器上抓包,看看两种请求方式有什么不一样
抓包命令如下
sudo tcpdump -i eth0 -A -n src <nginx服务器ip>
使用负载均衡地址localhost:9090/server_single/xxx 能看到抓到的请求头如下
GET /xxx HTTP/1.1
User-Agent: curl/7.29.0
Accept: */*
Host: server_single
使用服务器真实地址 http://192.167.1.125:8070/xxx 能看到的请求头如下
GET /xxx HTTP/1.1
User-Agent: curl/7.29.0
Accept: */*
Host: 192.167.1.125
查看到负载均衡模式下,请求头的Host: server_single 引起我的注意,猜想难道是因为Host 请求头的原因导致的400?,于是下面开始验证
- 直接访问后端真实接口的情况下带上Header Host: server_single 测试
命令如下
curl -H 'Host: server_single' 192.167.1.125:8080/xxx
接口如愿的返回了400的状态码,验证了我们的猜想
于是随便修改了几个 Host 字段常识,发现带下划线的都有问题,于是询问开发接口框架是否做了升级,回答说确实spring-boot 做了升级,所以基本确定就是这个原因。
解决办法
在nginx的location段增加配置 proxy_set_header Host $host ,修改反向代理nginx到真实Java接口请求时的Http header 。
location /server_single/ {
proxy_set_header Host $host;
proxy_pass http://server_single/;
}
结论
response_code = 400 表示客户端请求异常服务器,有可能是invalid hostname 也可能是其他 http header 导致服务器端无法正常解析。