如果我在发送包含 zip 文件的 HttpServletResponse
时未指定 Content-Length
header ,会发生什么情况?
我做了一些测试,似乎 header 默认设置为正确的文件长度。我能确定这种情况总是会发生吗?我什么时候可以找到一些相关文档?
最佳答案
如果实际响应内容长度完全适合响应缓冲区,通常为 2KB(取决于服务器 make/version/config),则将设置内容长度 header 。但是,如果实际响应内容长度大于响应缓冲区,因此会在到达响应内容末尾之前刷新它,则 servlet 将发送带有 chunked encoding 的响应。并忽略任何设置内容长度 header 的尝试。
HttpServlet#doGet()
的 javadoc 中提到了这一点引用如下:
...
Where possible, set the Content-Length header (with the
ServletResponse.setContentLength(int)
method), to allow the servlet container to use a persistent connection to return its response to the client, improving performance. The content length is automatically set if the entire response fits inside the response buffer.When using HTTP 1.1 chunked encoding (which means that the response has a Transfer-Encoding header), do not set the Content-Length header.
...
使用“正常”编码,数据作为一个连续 block 发送。
actualContent
使用分块编码,数据以如下所示的 block 形式发送
part1LengthInHexadecimal
actualPart1Content
part2LengthInHexadecimal
actualPart2Content
part3LengthInHexadecimal
actualPart3Content
0
十六进制的部分长度指示客户端下一个数据 block 有多大(这样它就不会“意外地”将下一个数据 block 解析为当前数据 block 的一部分)。最后,客户将各个部件粘合在一起。顺便说一句,这也是在响应上使用 Gzip 时的默认行为,因为最终内容长度事先未知。
另请参阅 wikipedia 中的示例.
请注意,当省略文件下载的内容长度时,用户体验将是文件下载进度未知。 IE。最终用户不会看到任何有关文件大小和剩余字节/时间的指示。如果这种用户体验对您很重要,那么您应该提前设置内容长度。您可以通过首先写入内存缓冲区(例如 new ByteArrayOuputStream(bytes)
)或临时文件(例如 Files#createTempFile()
)来完成此操作,这样您就可以获得通过 bytes.length
或 file.length()
确定内容长度,然后最终将该临时缓冲区/文件写入响应。
关于servlets - 我应该设置response.setContentLength() header 吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14381825/