坏块头的奥秘

最近,我在工作中的项目中遇到一个有趣的问题。 我正在处理许多基于Springboot的微服务,有时,使用RestTemplate exchange()方法后会引发异常:

org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.springframework.web.client.ResourceAccessException: I/O error on POST request for “...": Bad chunk header: {...}; nested exception is org.apache.http.MalformedChunkCodingException: Bad chunk header: {...} at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1014) at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909) at javax.servlet.http.HttpServlet.service(HttpServlet.java:660) at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) at javax.servlet.http.HttpServlet.service(HttpServlet.java:741) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)

Below is the simplified sequence diagram:
Diagram

经过调查,这是我发现的有关此问题的信息:

  • 服务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 request is succeeded and response is returned. But is it true???异常消息很短,但仍然留下了重要提示:标头. Did service A receive an inappropriate 标头, or more correctly, service B sent an unwanted 标头? How can we know what 标头是错的?

进一步调查,我发现服务B只是将请求转发到服务C,然后将响应从服务C转发到服务A。类似这样的东西:

public ResponseEntity<?> forwardRequest(@RequestBody Request request) {
    return restTemplate.exchange(url, HttpMethod.POST, request, ...)
}

如果是这样,不合适的标头不是来自服务B,而是来自服务C吗?

幸运的是,我们可以插入代码来记录服务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 request. 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

现在我们知道,盲目转发响应而不过滤出标头是一种不好的做法。 如果您不关心标题,只需提取并返回仅响应主体就足够了。

Øriginally published at rey5137.com

from: https://dev.to//rey5137/bad-chunk-header-mystery-3bdo

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值