2014-03-25 38 views
4

我们正在尝试使用mod_xsendfile和Apache来有效地处理大文件下载(> 1 GB)。安装后的配置是这样的:mod_xsendfile Firefox恢复问题

<IfModule mod_xsendfile.c> 
<Directory "/abs_path/to/dl"> 
    XSendFile on 
    XSendFilePath /abs_path/to/files_dir 
</Directory> 
</IfModule> 

下载脚本确实没有什么花哨,只检查文件是否存在,下载并设置标题为每文档,像这样:

header("Content-type: application/octet-stream"); 
header('Content-Disposition: attachment; filename="' . basename($file) . '"'); 
header("X-Sendfile: " . $file); 

不间断下载工作使用我们测试过的任何用户代理都可以,并且HTTP-Range对除Firefox以外的所有用户(测试版本27和28)都可以正常工作。 Firefox可以暂停下载,但每次恢复失败。

这些是活HTTP头扩展捕获的HTTP标头:

初始下载:

http://www.oursite.com/dl/test-xs.php?ID=TestFileID 

GET /dl/test-xs.php?ID=TestFileID HTTP/1.1 
Host: www.oursite.com 
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:27.0) Gecko/20100101 Firefox/27.0 
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 
Accept-Language: en-gb,en;q=0.5 
Accept-Encoding: gzip, deflate 
Cookie: some cookie string... 
Connection: keep-alive 

HTTP/1.1 200 OK 
Date: Tue, 25 Mar 2014 10:22:46 GMT 
Server: Apache 
X-Powered-By: PHP/5.3.28 
Content-Disposition: attachment; filename="TestFile.ext" 
Last-Modified: Sun, 02 Mar 2014 18:20:36 GMT 
Content-Length: 84406272 
Connection: close 
Content-Type: application/octet-stream 

...当Firefox的尝试恢复:

http://www.oursite.com/dl/test-xs.php?ID=TestFileID 

GET /dl/test-xs.php?ID=TestFileID HTTP/1.1 
Host: www.oursite.com 
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:27.0) Gecko/20100101 Firefox/27.0 
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 
Accept-Language: en-gb,en;q=0.5 
Accept-Encoding: gzip, deflate 
Cookie: same cookie string... 
Connection: keep-alive 
Range: bytes=11238434- 
If-Unmodified-Since: Sun, 02 Mar 2014 18:20:36 GMT 

...服务器返回404

HTTP/1.1 404 Not Found 
Date: Tue, 25 Mar 2014 10:23:03 GMT 
Server: Apache 
X-Powered-By: PHP/5.3.28, PHP/5.3.28 
Content-Disposition: attachment; filename="TestFile.ext" 
X-Sendfile: /abs_path/to/files_dir/TestFile.ext 
X-Pingback: http://www.oursite.com/xmlrpc.php 
Expires: Wed, 11 Jan 1984 05:00:00 GMT 
Cache-Control: no-cache, must-revalidate, max-age=0 
Pragma: no-cache 
Connection: close 
Transfer-Encoding: chunked 
Content-Type: text/html; charset=UTF-8 

......这明显会导致Firefox无法恢复下载(现在只能从开始取消并重新启动)。

考虑一切正常在其他浏览器和下载管理器,我们已经试过:

  1. 有没有人遇到过类似的行为?
  2. 任何人都可以在我们的 下载脚本或配置代码中解释或指出它的潜在原因吗?

编辑

做更多的一些测试结果证明,问题是下降到恢复下载时If-Unmodified-Since头被火狐发送之后。即使此标头正确设置为从Apache接收到的Last-Modified响应标头的值,服务器也不会因为某种原因而喜欢它,并以404作出响应。通过改变从的.htaccess要求剥离If-Unmodified-Since头之后:

<Files test-xs.php> 
    RequestHeader unset If-Unmodified-Since 
</Files> 

...恢复正常工作无处不在,包括Firefox浏览器。

如果要下载的文件同时被修改,但这种方法当然是不正确的,但它为我们完成了这项工作,因为我们使用不同的约定来提供同一文件的较新版本。

这显然更像是一个黑客而不是一个正确的实现,所以不能确定这是否应该被标记为答案,我将它作为原始问题的补充。

新的问题出现明显:

  • 有没有更好的办法来解决这个问题?
  • 这是mod_xsendfile中的错误吗?

回答

0

mod_xsendfile似乎不适用于浏览器发送的一些缓存头。

第一请求头:

GET /foo.webm 

Range: bytes=0- 

第一响应标头:

206 Partial Content 

Content-Length: 54376097 
Content-Range: bytes 0-54376096/54376097 
Content-Type: video/webm 
ETag: "78976c9d1a595cba56e24bec6f2f1178" 
例如,铬恢复与一个“范围”报头中的下载时,发送一个“如果型”报头

=>视频开始播放正常

现在,用户会磨擦到稍后的位置离子在文件中

第二请求报头:

GET /foo.webm 

If-Range: "78976c9d1a595cba56e24bec6f2f1178" 
Range: bytes=54373845-54376096 

第二响应标头:

200 OK 

Content-Length: 54376097 
ETag: "78976c9d1a595cba56e24bec6f2f1178" 

=>整个文件被发送请求的字节范围的代替

解决方法

未设置有问题的请求头,如果“范围”头存在:

SetEnvIf Range .+ HAS_RANGE_HEADER 
RequestHeader unset If-Range env=!HAS_RANGE_HEADER 
RequestHeader unset If-Unmodified-Since env=!HAS_RANGE_HEADER 
1

@alternize's solution大多是正确的,但所提供的片段:

SetEnvIf Range .+ HAS_RANGE_HEADER 
RequestHeader unset If-Range env=!HAS_RANGE_HEADER 
RequestHeader unset If-Unmodified-Since env=!HAS_RANGE_HEADER 

实际上不会取消设置指定头的请求包含一个Range标题。

''取消匹配,所以上面的代码段实际上将取消设置所有请求的标头,但标头的标头为Range

要正确使用Range头删除请求If-RangeIf-Unmodified-Since头,您可以使用相同的指令,但删除的否定这样:

SetEnvIf Range .+ HAS_RANGE_HEADER 
RequestHeader unset If-Range env=HAS_RANGE_HEADER 
RequestHeader unset If-Unmodified-Since env=HAS_RANGE_HEADER 

这已被证实在Apache 2.2.15 。