问题 如何在Android中明确禁用HTTP连接的分块流模式?


我的目标是从Android 4.0使用REST Web服务 HttpsURLConnection。除非我尝试,否则此工作正常 POST 一些东西。这是相关的代码部分:

   connection.setDoOutput(true);
   connection.setChunkedStreamingMode(0);

   ByteArrayOutputStream out = new ByteArrayOutputStream();
   serializeObjectToStream(out, object);
   byte[] array = out.toByteArray();
   connection.getOutputStream().write(array, 0, array.length);

这会引发以下异常:

   java.net.HttpRetryException: Cannot retry streamed HTTP body

从调试我意识到我得到的输出流 connection.getOuputStream() 是类型 ChunkedOutputStream 并且从挖掘Androids源代码中我发现,如果需要重试请求(无论出于何种原因),它会引发上述异常,因为它会发现它是  用一个 RetryableOutputStream 它想要那里。

现在的问题是:如何使我的HttpsURLConnection返回这样的RetryableOutputStream,或者更确切地说,如何正确地阻止分块请求编码?一世 思想 我已经这样做了 setChunkedStreamingMode(0),但显然事实并非如此......

[编辑]

不,执行 java.net.HTTPUrlConnection 忽略0或更低的流模式:

 public void setChunkedStreamingMode(int chunkLength) {
    [...]
    if (chunkLength <= 0) {
        this.chunkLength = HttpEngine.DEFAULT_CHUNK_LENGTH;
    } else {
        this.chunkLength = chunkLength;
    }
}

8738
2017-08-22 10:36


起源

在相关的说明:我认为原因 为什么 它想要一个RetryableOutputStream,因为在REST服务器上配置了基本身份验证保护,Android的HttpURLConnectionImpl似乎会在获得401 Unauthorized答案时自动重试请求。 - Thomas Keller


答案:


坏消息!解决方案是不打电话 setChunkedStreamingMode() (甚至 setFixedStreamingMode())来自客户端代码! “-1”是fixedLength和chunkedLength的内部默认值,不能设置为客户端,因为设置值小于或等于“0”会使其默认为 HttpEngine.DEFAULT_CHUNK_LENGTH (或在固定流模式情况下抛出异常)。


12
2017-08-27 12:12





解决方案是设置一个 Content-Length 标题(可以由下一部分设置)并调用 setFixedLengthStreamingMode 使用您要发送的POST消息的正确长度。

请参阅此SO常见问题解答中的“流媒体模式”部分:

使用java.net.URLConnection来触发和处理HTTP请求


1
2017-08-29 23:52



你永远不应该设置 Content-length Java中的标题。 setFixedLengthStreamingMode() 无论如何都会这样做,并覆盖已设置的内容。 NB如果你打电话 setChunkedStreamingMode() 那里 是 没有 Content-length 标题,你绝对不应该设置一个。如果你不调用这些方法中的任何一个, HttpURLConnection 将它自己设置为正确的值。 - user207421
@EJP也许我的评论不清楚,但我试图暗示这一点 setFixedLengthStreamingMode 会为你设置标题。最初的问题显然是请求一个非分块的请求,以便它可以“重试”。原来的海报也回复道 6年前 说任何电话 set*StreamingMode 会打破这个。所以,手动设置 Content-Length 在某些条件下确实有意义。 - Christopher Schultz