为什么Content-Length HTTP头字段使用与Java代码中给定值不同的值?

6

我有一段Java代码,用于将字节数组传输到HTTP服务器:

HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoInput(true);
connection.setDoOutput(true);
connection.setUseCaches(false);
connection.setRequestMethod("POST");
connection.setRequestProperty("Connection", "Keep-Alive");
connection.setRequestProperty("Content-Type", "multipart/form-data; boundary="
    + myBoundary);
connection.setRequestProperty("Content-Length", 1024);

我使用了这段代码来传输一个大小超过1024的字节数组,它运行良好。但是实际的HTTP消息(被Wireshark捕获)显示Content-Length的值是实际大小而不是1024。为什么?
我在HTTP规范中搜索,但没有找到任何线索。我没有使用任何Transfer-Encoding或Transfer-coding。
2个回答

16
我猜测 HttpURLConnection 将会用正确的值覆盖 Content-Length 头部,因为它 知道 欺骗是不好的;确实如此:在 sun.net.www.protocol.HttpURLConnection 的第 535 至 550 行中,如果适用,则设置了 Content-Length。这发生在用户指定的头部设置之后,因此该值将被覆盖。
这是正确的,如果传输的数据量与所声称的数据量不匹配,则只会让另一端感到困惑。
检查 源代码中的 sun.net.www.protocol.http.HttpURLConnection,似乎有一系列受限制的头部,调用 setRequestProperty 时将被静默忽略。其中包括 Content-Length。不幸的是,这似乎没有记录在案(至少我没有找到任何文档,仅在这里讨论了一个相关问题)。

在搜索引擎中搜索引入此"功能"的更改集中提到的Bug ID (?),似乎这个更改是为了应对安全漏洞CVE-2010-3541CVE-2010-3573关于此主题的Redhat bug)而引入的。

可以通过在JVM启动时将系统属性sun.net.http.allowRestrictedHeaders设置为true来手动禁用该限制。


“Content-Length”的值被错误地硬编码了。令我惊讶的是它竟然能正常工作。我想知道为什么。 - chance
你的猜测听起来很合理。但是在哪里找到相关文档呢? - chance
@joachim-sauer:非常好的回答!但是我已经测试了sun.net.http.allowRestrictedHeaders=true,发现结果与之前相同。 - chance
@wang:我的长篇分析在这里并不适用,因为“Content-Length”将被正确的值覆盖。我已经更新了我的答案。 - Joachim Sauer

0

这个对我解决了问题:

connection.setFixedLengthStreamingMode(myString.getBytes().length);
conn.setRequestProperty("Content-length", String.valueOf(myString.getBytes().length));

在设置Content-Length头之前,使用"connection.setFixedLengthStreamingMode(myString.getBytes().length);"。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接