某次定位请求,发现400 bad request,抓包发现请求头如下
POST /xx/xx/user/default/subscribe HTTP/1.1
Authorization: xx
Host: http://100.40.205.122:8080
Content-Type: application/json;charset=utf-8
Content-Length: 248
Connection: Keep-Alive
User-Agent: Apache-HttpClient/4.3.1 (java 1.5)
Accept-Encoding: gzip,deflate
可能有同学一眼就看出来,问题出在Host字段多了个http://
tomcat是怎么解析Host头的呢?以7.0.70为例,参考AbstractHttp11Processor.parseHost 方法,首先判断是否是ipv4的ip,如果是,用:分隔,左边为ip,右边为端口;如果没有:则根据url里开头是http还是https分别设置端口为80/443,所以这里400就是因为:分隔之后端口非数字,挂了,解析port代码如下
int port = 0;
int mult = 1;
for (int i = valueL - 1; i > colonPos; i--)
{
int charValue = HexUtils.getDec(valueB[i + valueS]);
if (charValue == -1 || charValue > 9)
{
// Invalid character
// 400 - Bad request
response.setStatus(400);
setErrorState(ErrorState.CLOSE_CLEAN, null);
break;
}
port = port + (charValue * mult);
mult = 10 * mult;
}
Host头,是http协议中唯一要求必填的头,为什么呢?以tomcat为例,假设有2个应用位于webapps下分别为baidu和alibaba,在server.xml配置2个Host,而且appBase都是webapps,那么ip和端口都是一样的,到达tomcat后应该给哪个应用呢?这时候可不就得依赖于Host头了吗