最近,我在工作中的项目中遇到一个有趣的问题。我正在研究许多基于Springboot的微服务,有时,在使用RestTemplate交换()方法后会引发异常:
org。springframework。web。util。NestedServletException:请求处理失败;嵌套的异常是org.springframework.web.client.ResourceAccessException:开机自检请求“...”时发生I / O错误:错误的块头:{...};嵌套的异常是org.apache.http.MalformedChunkCodingException:错误的块 标头:{...},位于javax.servlet的org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909)的org.springframework.web.servlet.FrameworkServlet.process请求(FrameworkServlet.java:1014)。 org处的org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)处的http.HttpServlet.service(HttpServlet.java:660)org处的javax.servlet.http.HttpServlet.service(HttpServlet.java:741) org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)上的.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)在org.apache.tomcat.websocket.server.WsFilter.doFilter (WsFilter.java:53)在org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)在o rg.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
经过调查,这是我发现的有关此问题的信息:
- 服务A收到服务B的响应后,将引发异常。
- 仅当我运行一些性能测试案例使服务A充满请求时,才会发生此问题。
- 这个问题是相当一致的,尽管不是确切的时间,但是在我运行测试用例的大多数时候都会发生。
- The interesting thing here is the log from service B & C didn’t show anything wrong when this issue happened, indicated that 请求 is succeeded and response is 返回ed. But is it true???
- 异常消息很短,但仍然留下了重要提示:标头。 服务A是否收到了不合适的标头,或更正确地说,服务B是否发送了不需要的标头? 我们怎么知道标头是错的?
进一步调查,我发现服务B只是将请求转发到服务C,然后将响应从服务C转发到服务A。类似这样的东西:
上市 响应实体<?> forward请求(@RequestBody Request 请求) {返回 restTemplate.交换(网址, HttpMethod.开机自检, 请求, ...)
}
If so, did the inappropriate header not come from service B, but from service C instead?
幸运的是,我们可以插入代码来记录服务C响应的所有标头。 添加并重新运行测试用例后,这是发生异常时得到的信息:
Header: [Connection] > [close]
Header: [Content-Type] > [application/json;charset=UTF-8]
Header: [Date] > [DD/mm/yyyy]
Header: [Transfer-Encoding] > [chunked]
为了简便起见,以下是正常回复的标题:
Header: [Content-Type] > [application/json;charset=UTF-8]
Header: [Date] > [DD/mm/yyyy]
Header: [Transfer-Encoding] > [chunked]
最后,我们可以看到罪魁祸首。 是标题连接方式:关闭服务C返回并且服务B盲目返回服务A。
但是是什么连接方式:关闭意思? 以及它如何包含在服务C响应中?
From RFC 2616, Section 14.10 , Connection: close is included to signal that the connection will be closed after completion of the response. Normally, connection with keepAlive property will not be closed by the server so the client can keep using it for another 请求. But tomcat has a max-keepalive-timeout setting, that will close connection that reaches a certain keepAlive time. And that is when the server will include Connection: close header.
Conclusion
现在我们知道,盲目转发响应而不过滤出标头是一种不好的做法。 如果您不关心标题,只需提取并返回仅响应主体就足够了。
Originally published at rey5137.com
from: https://dev.to//rey5137/bad-chunk-header-mystery-3bdo