最近做一个特性,需要两个微服务间通信A->B,A为SpringCloudGateway架构,B为SpringCloud架构,死活调不通,返回html错误页
HTTP Status 400 – Bad Request
以下是解决过程:
1、查看A、B服务的日志,均没有错误
2、在A容器中curl B接口正常
3、tcpdump抓包,由于用的加密算法无法解码,只能看到A与B通信正常,最后是B FIN断开
4、使用arthas工具在A容器中调试,获取A发送出的地址URL均正常,获取到相应码400,说明是B返回了400
5、使用arthas工具在B容器中调试,发现没有进入业务代码,但消息肯定是B返回的,说明在业务代码之前的框架中就异常了。
本地启动B服务,调用相同的接口DEBUG得到调用栈,根据调用栈在线上的B服务上逐步缩小排查范围。
定位到返回400是由于org.apache.coyote.Response#isError为true,而正常的流程是false,继续分析找到设置为true的方法AbstractProcessor.setErrorState(ErrorState errorState,Throwable t),并使用如下命令可以观察到请求参数Throwable:
watch org.apache.coyote.AbstractProcessor setErrorState "{params}" -n 1000000 -x 3
再次发送消息,可以得到如下结果:
java.lang.IllegalArgumentException: Request header is too large
at org.apache.coyote.http11.Http11InputBuffer.parseHeaders(Http11InputBuffer.java:603)
发现问题所在:Request header is too large。由于消息请求中有一个较长的头域导致。
6、进一步使用命令查看到B微服务使用的是默认限制8192
watch org.apache.coyote.http11.Http11InputBuffer parseHeaders "{target.headerBufferSize}" -n 1000000 -x 3
@Integer[8192]
7、然而查看application.yml中配置的却是65535,该配置未生效
server:
max-http-header-size: 65536
8、全局搜索max-http-header-size找到spring的元数据配置文件:
spring-configuration-metadata.json
{
"name": "server.max-http-header-size",
"type": "org.springframework.util.unit.DataSize",
"description": "Maximum size of the HTTP message header.",
"sourceType": "org.springframework.boot.autoconfigure.web.ServerProperties",
"defaultValue": "8KB"
}
其中规定了是以DataSize格式配置,65536格式不合法,将其改成64KB上线后验证OK