2014-03-25 37 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 。