HttpClient抛出TruncatedChunkException访问大块的资源

时间:2013-09-16 05:24:28

标签: java apache http httpclient chunked

[使用httpcore 4.1.4,httpclient 4.2.5,Oracle JDK 1.7.0_25]

我正试图代表webapp的javascript(AJAX)代码“代理”与第三方Web服务的连接,并且它似乎在大chunked个响应中失败,错误地通过一个块的错误发送多个RST并抛出org.apache.http.TruncatedChunkException

所以我想知道:

  1. 为什么http客户端试图断开连接?
  2. 它做了什么明智的事情? (即服务器可能有故障)或者这里有什么车吗?
  3. 我的基本方法是将所有内容从servlet的请求对象复制到apache组件httpclient请求并执行。更具体地说,我:

    1. 创建一个apache commons httpclient DefaultHttpClient对象,
    2. 将所有请求标头复制到新的请求对象
    3. 使用我所代理的主机/端口设置(/覆盖)新请求中的host标头,
    4. 将所有HTTP参数复制到新请求
    5. 将任何实体主体复制到新请求
    6. 执行请求,
    7. 将响应标头复制到我的servlet的响应标头和
    8. 将任何实体主体作为流复制到servlet的输出流。
    9. 引起我问题的是最后一个问题。它似乎在一大块中途失败了,我得到了以下的堆栈跟踪:

      org.apache.http.TruncatedChunkException: Truncated chunk ( expected size: 7752; actual size: 4077)
      at org.apache.http.impl.io.ChunkedInputStream.read(ChunkedInputStream.java:186)
      at org.apache.http.conn.EofSensorInputStream.read(EofSensorInputStream.java:138)
      at <mypackage>.<MyServlet>.service(<MyServlet>.java:XXX)
      at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
      at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
      at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
      at org.jboss.resteasy.plugins.server.servlet.FilterDispatcher.doFilter(FilterDispatcher.java:63)
      at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
      at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
      at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
      at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
      at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
      at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
      at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
      at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:293)
      at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:859)
      at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:602)
      at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489)
      at java.lang.Thread.run(Thread.java:724)
      

      我已经使用Wireshark窥探了它并得到了类似这样的过程:

      source  dest    info
      client  server  [SYN] seq=0
      server  client  [SYN, ACK] seq=0 ack=1
      client  server  [ACK] seq=1 ack=1
      client  server  GET /url?param=value... HTTP/1.1
      server  client  [ACK] seq=1 ack=221
      server  client  [TCP segment of a reassembled PDU]
      client  server  [ACK] seq=221 ack=4345
      client  server  [FIN, ACK] seq=221 ack=4345
      server  client  [TCP segment of a reassembled PDU]
      client  server  [RST] seq=221
      server  client  Continuation or non-HTTP traffic
      client  server  [RST] seq=221
      

      在我的有限理解FIN means 'I'm done sending'中,由于客户端标题已经发送,因此IMO是公平的。但是,RST / reset似乎只是试图放弃连接。

      客户端的HTTP标头是:

      GET /some/path?params=values HTTP/1.1
      connection: Keep-Alive
      host: target.host.com
      accept: */*
      user-agent: Wget/1.14 (linux-gnu)
      

      对于服务器:

      HTTP/1.1 200 OK
      Date: Mon, 16 Sep 2013 03:59:37 GMT
      Server: Apache-Coyote/1.1
      Content-Disposition: inline; filename=geoserver-GetFeature.text
      Content-Type: text/xml; subtype=gml/2.1.2
      Vary: Accept-Encoding
      Connection: close
      Transfer-Encoding: chunked
      
      不过,这个问题:[restlet ]TruncatedChunkException:看起来很相似,但似乎没有任何有用的信息。

      更新:我尝试过使用非分块网站(/。:-)),它的失败程度与:

      org.apache.http.ConnectionClosedException: Premature end of Content-Length delimited message body
      

1 个答案:

答案 0 :(得分:7)

好的,我发现了我的所作所为。我太早清理了我的连接 - 基本上我的连接方法中的样板文件有一个

finally
{
    client.getConnectionManager().shutdown();
}

但该方法返回了流对象,因此在关闭发生时没有完成读取。