【问题标题】:Unexpected content at the end of chunk - what builds the corrupt stream?块末尾的意外内容 - 是什么构建了损坏的流?
【发布时间】:2019-08-30 19:12:24
【问题描述】:

我遇到了一个返回大约 900k XML 的端点。时不时地(在今天的测试中不到 5000 分之一)我得到一个 MalformedChunkCodingException

这是在 Spring 3 上构建的相当老的 webapp(约 10 年)中发生的。我转而直接使用 RestTemplate 而不是 httpclient,但这并没有解决它。今天在 httpclient 上启用了线级日志记录运行了几个小时后,我设法捕获了一个。

Caused by: org.apache.http.MalformedChunkCodingException: Unexpected content at the end of chunk
    at org.apache.http.impl.io.ChunkedInputStream.getChunkSize(ChunkedInputStream.java:259)
    at org.apache.http.impl.io.ChunkedInputStream.nextChunk(ChunkedInputStream.java:227)
    at org.apache.http.impl.io.ChunkedInputStream.read(ChunkedInputStream.java:186)
    at org.apache.http.conn.EofSensorInputStream.read(EofSensorInputStream.java:137)
    at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:284)
    at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:326)
    at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178)
    at java.io.InputStreamReader.read(InputStreamReader.java:184)
    at java.io.Reader.read(Reader.java:140)
    at org.springframework.util.StreamUtils.copyToString(StreamUtils.java:74)
    at org.springframework.http.converter.StringHttpMessageConverter.readInternal(StringHttpMessageConverter.java:85)
    at org.springframework.http.converter.StringHttpMessageConverter.readInternal(StringHttpMessageConverter.java:40)
    at org.springframework.http.converter.AbstractHttpMessageConverter.read(AbstractHttpMessageConverter.java:153)
    at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:103)
    at org.springframework.web.client.RestTemplate$ResponseEntityResponseExtractor.extractData(RestTemplate.java:724)
    at org.springframework.web.client.RestTemplate$ResponseEntityResponseExtractor.extractData(RestTemplate.java:709)

通常日志看起来是这样的:

DEBUG org.apache.http.wire - << "words words words"
DEBUG org.apache.http.wire - << "[\r][\n]"
DEBUG org.apache.http.wire - << "FAF[\r][\n]"
DEBUG org.apache.http.wire - << "words words words up to FAF bytes" 
DEBUG org.apache.http.wire - << "[\r][\n]"
DEBUG org.apache.http.wire - << "BAA[\r][\n]"
DEBUG org.apache.http.wire - << "words words words up to BAA bytes"

但在出错的那一个中,我有这个:

DEBUG org.apache.http.wire - << "words words words"
DEBUG org.apache.http.wire - << "[\r][\n]"
DEBUG org.apache.http.wire - << "B50[\r][\n]"
DEBUG org.apache.http.wire - << "words words words up to B50 bytes"
DEBUG org.apache.http.wire - << "3FC0[\r][\n]"

它缺少 B50 块末尾的 [\r][\n]。

所以,假设我可以信任 org.apache.http.wire 调试,那么我的应用程序正在接收这样的流,而且它的格式不正确。它们之间的 haproxy 是否有可能破坏了流?

幸运与否,对话的另一端也是我的应用程序之一,在 Spring 4.2.4 的 tomcat 中运行。

我从哪里开始寻找谁在构建无效响应?春天?雄猫?

看起来我可以禁用分块,但我只是在构建响应时计算我的内容长度,我并不热衷于这样做,因为那样我将不得不手动序列化我的响应,而不是让 Spring去做吧。

【问题讨论】:

    标签: java spring http tomcat chunked-encoding


    【解决方案1】:

    正如您所说,该应用程序已经很旧了。您可能需要更新所有库版本,希望该问题已被检测到并在某处得到修复。

    但是找到坏演员会有所帮助,因为你只需要修复那个。

    根据我自己在 HTTP 工具中测试不良语法支持的经验,我很确定 Haproxy 是您列出的元素中更健壮的元素。但这并不排除那里的问题。

    发送和接收端点之间的每个 HTTP 参与者都可以更改 HTTP 主体(重做块大小),因此您需要捕获所有参与者(spring、tomcat、haproxy、任何其他代理和/或反向)的输入和输出代理、负载平衡器、ssl 终结器)来检测坏块。我将从消息发射器、XML 端点开始。我会使用 wireshark/pcap/httpdump,真正捕获 TCP 和 HTTP 流量的东西。但是您可能必须找到一种方法来快速丢弃捕获,直到达到失败点,因为 1/5000 意味着您有很大的风险捕获大量数据。

    【讨论】:

      【解决方案2】:

      我花了一个月的时间对此进行测试。虽然我缺乏 100% 确定的答案,但我发现:

      使用 haproxy 版本 1.7.x 运行时,我无法触发错误。

      使用 haproxy 版本 2.0.x 运行时,我偶尔会触发错误。

      这可能与此有关,也可能无关:

      https://github.com/haproxy/haproxy/issues/171

      【讨论】:

        猜你喜欢
        • 2014-09-13
        • 1970-01-01
        • 2016-01-10
        • 2012-10-31
        • 1970-01-01
        • 1970-01-01
        • 2012-05-07
        • 2011-01-15
        • 2013-01-31
        相关资源
        最近更新 更多