公司项目由于业务需要,将tomcat6升级为tomcat9后,记一次踩坑过程。
问题描述:
服务启动后,使用postman等工具发送POST请求可正常响应,下级服务器拼接请求发送后返回400错误码。
解决方案:
进入Tomcat/conf文件夹,修改server.xml内Connector标签,添加allowHostHeaderMismatch="True",即可解决。
<Connector port="80" allowHostHeaderMismatch="true"/>
排查过程:
首先排除了底层协议拼接错误,因为在原有版本的服务器上是可以正常通讯,只在新版tomcat上返回400,而使用postman又可以正常通讯,所以我认为是tomcat9中对请求头的解析进行了修改。
b'''POST http://127.0.0.1:80/***/*** HTTP/1.1
Accept: image/gif, */*
Referer: http://127.0.0.1/index.html
Accept-Language: zh-cn
Content-Type: multipart/form-data
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)
Host: 127.0.0.1
Content-Length: 3
Proxy-Connection: Keep-Alive
Pragma: no-cache123'''
以上是原有请求头。后面经过逐步对比,发现是host未指定端口,在host后面指定端口,就可以正常请求,但是因为业务特殊,下级服务器更换程序成本较高,所以理想情况下是更改tomcat配置。
排查过程:
首先是下载了tomcat9的源码,按照网上的配置进行启动后,一步一步debug,发现在
org.apache.coyote.http11.Http11Processor
类中有如下处理:
if (http11) {
// Missing host header is illegal but handled above
if (hostValueMB != null) {
// Any host in the request line must be consistent with
// the Host header
if (!hostValueMB.getByteChunk().equals(
uriB, uriBCStart + pos, slashPos - pos)) {
if (protocol.getAllowHostHeaderMismatch()) {
// The requirements of RFC 2616 are being
// applied. If the host header and the request
// line do not agree, the request line takes
// precedence
hostValueMB = headers.setValue("host");
hostValueMB.setBytes(uriB, uriBCStart + pos, slashPos - pos);
} else {
// The requirements of RFC 7230 are being
// applied. If the host header and the request
// line do not agree, trigger a 400 response.
badRequest("http11processor.request.inconsistentHosts");
}
}
}
}
getAllowHostHeaderMismatch()方法就是是否检查请求头。
为了印证猜想,在Tomcat的conf文件夹内,添加了allowHostHeaderMismatch
后来在查看tomcat更新日志后发现有提到这个更新说明。
Enable strict validation of the provided host name and port for all connectors. Requests with invalid host names and/or ports will be rejected with a 400 response. (markt)
Implement the requirements of RFC 7230 (and RFC 2616) that HTTP/1.1 requests must include a
Host
header and any request that does not must be rejected with a 400 response. (markt)Implement the requirements of RFC 7230 that any HTTP/1.1 request that specifies a host in the request line, must specify the same host in the
Host
header and that any such request that does not, must be rejected with a 400 response. This check is optional and disabled by default. It may be enabled with theallowHostHeaderMismatch
attribute of the Connector. (markt)Implement the requirements of RFC 7230 that any HTTP/1.1 request that contains multiple
Host
headers is rejected with a 400 response. (markt)62273: Implement configuration options to work-around specification non-compliant user agents (including all the major browsers) that do not correctly %nn encode URI paths and query strings as required by RFC 7230 and RFC 3986. (markt)
总结:
类似问题,一定要先去官方的更新日志找找。如果一开始先去看了日志,省去不少功夫!!!血与泪的教训!