使用GZIP和字节范围同时发送HTTP响应是否可行?

4

请求:

...
Content-Range: bytes 27482871-41601067/41601068
...

我尝试从文件中读取字节,然后进行GZIP压缩。响应结果如下:

response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);

...
Server: GlassFish Server Open Source Edition  4.1
X-Powered-By: Servlet/3.1 JSP/2.3 (GlassFish Server Open Source Edition  4.1  Java/Oracle Corporation/1.8)
Date: Thu, 26 Nov 2015 21:44:21 GMT
Accept-Ranges: bytes
Connection: keep-alive
Keep-Alive: timeout=1800
Content-Disposition: attachment;filename*=utf-8''Marq_Aurel_Rayman_Rave_-_Intdo_The_Blue_%28Max_R_remix%29.wav
ETag: Marq_Aurel_Rayman_Rave_-_Intdo_The_Blue_%28Max_R_remix%29.wav-41601068-1403655006000
Cache-Control: private,max-age=604800
Last-Modified: Wed, 25 Jun 2014 00:10:06 GMT
Content-Range: bytes 27482871-41601067/41601068
Content-Encoding: gzip
...

如果我暂停并恢复下载,下载会失败。也许我在范围响应中不应该使用GZIP?

1个回答

8
是的。可以通过Transfer-Encoding来请求gzip压缩过的内容,但是不能使用Content-Encoding
如果您请求一定范围内的字节,并且使用Content-Encoding,将无法正常工作。这意味着服务器对整个文档进行了编码,如果整个内容都使用gzip编码,而您只请求其中的一部分,则无法解压缩。 (您不能解压缩部分gzip,或者至少没有它的开头。)
相反,您可以使用Transfer-Encoding来服务于您想要的范围,并压缩该范围。更好!
令人费解的是,虽然您使用Accept-Encoding标题请求Content-Encoding,但您使用TE标题请求Transfer-Encoding
然而,这就是问题的症结所在:很少有Web服务器支持此功能。例如,如果您从CloudFlare拉取内容,则会发现他们不支持。
这里是nginx邮件列表上的讨论,其中讨论了这个问题,这里是另一个关于在HTTP / 2中使其工作的讨论

字节范围是原始未压缩有效负载还是压缩后的有效负载?我猜应该是前者?我认为是这样,因为据我所知每个块都是单独压缩的。 - Khoi
1
@Khoi 是的,没错!你是在服务器存储的内容方面指定了一个范围。这里没有Content-Encoding - Aidan Fitzpatrick
1
后来我发现在Chrome中不能发送TE头,也无法解析Transfer-Encoding: gzip, chunked响应。感觉我们距离在浏览器中看到这个还有很多年的时间。 - Khoi
我认为答案是不正确的,如在nginx论坛中所解释的。还有这个w3标准邮件列表上的来源,它说您可以请求内容编码有效负载的范围。 - Tangui
1
这些链接肯定支持答案:“Content-Encoding: gzip实际上是一个误称,因为在大多数情况下它实际上被用作传输编码”,“范围请求+gzip压缩提供了巨大的性能提升,但由于所述原因,在不使用gzip传输编码的情况下(以符合标准的方式)是不可能的”。RFC允许请求的内容与许多服务器支持的内容之间存在差异! - Aidan Fitzpatrick

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