題 為什麼有些下載文件不知道自己的大小? [重複]


這個問題在這裡已有答案:

有時,在Web瀏覽器中下載文件時,下載進度不會“知道”文件的總大小,也不會“知道”下載的距離 - 它只顯示下載文件的速度,總計為“未知”。

為什麼瀏覽器不知道某些文件的最終大小?它首先從哪裡獲得這些信息?


79
2017-07-09 05:44


起源


動態創建的文件沒有大小,它們作為流來到達,直到達到EOF。 - Fiasco Labs
可能重複 瀏覽器如何知道已加載了多少頁面?, 下載時未顯示估計的剩餘時間和總文件大小 ... - Karan


答案:


要從Web服務器請求文檔,瀏覽器使用HTTP協議。您可能從地址欄中知道該名稱(現在可能已隱藏,但當您單擊地址欄時,複製URL並將其粘貼到某個文本編輯器中,您會看到 http:// 在開始)。 HTTP是一種簡單的基於文本的協議。它的工作原理如下:

首先,您的瀏覽器連接到網站的服務器並發送它想要下載的文檔的URL(網頁也是文檔)以及有關瀏覽器本身的一些詳細信息(用戶代理 等等)。例如,要在SuperUser站點上加載主頁面, http://superuser.com/,我的瀏覽器發送一個如下所示的請求:

GET / HTTP/1.1
Host: superuser.com
Connection: keep-alive
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.0 Safari/537.36
Accept-Encoding: gzip,deflate,sdch
Accept-Language: pl-PL,pl;q=0.8,en-US;q=0.6,en;q=0.4
Cookie: [removed for security]
DNT: 1
If-Modified-Since: Tue, 09 Jul 2013 07:14:17 GMT

第一行指定服務器應返回的文檔。 其他行稱為標題;它們看起來像這樣:

Header name: Header value

這些行發送有助於服務器決定做什麼的其他信息。

如果一切正常,服務器將通過發送請求的文檔進行響應。 響應從狀態消息開始,然後是一些標題(包含有關文檔的詳細信息),最後,如果一切正常,則是文檔的內容。這就是SuperUser服務器對我的請求的回復如下:

HTTP/1.1 200 OK
Cache-Control: public, max-age=60
Content-Type: text/html; charset=utf-8
Expires: Tue, 09 Jul 2013 07:27:20 GMT
Last-Modified: Tue, 09 Jul 2013 07:26:20 GMT
Vary: *
X-Frame-Options: SAMEORIGIN
Date: Tue, 09 Jul 2013 07:26:19 GMT
Content-Length: 139672

<!DOCTYPE html>
<html>
    [...snip...]
</html>

在最後一行之後,SuperUser的服務器關閉連接。

第一行(HTTP/1.1 200 OK)包含 響應代碼,在這種情況下它是 200 OK。這意味著服務器已經決定它可以根據請求返回文檔,並承諾後面的內容將是這樣的文檔。如果不是這種情況,則代碼將是其他內容,並且它將提供服務器不僅僅返回文檔作為響應的原因的一些指示:例如,如果它找不到所請求的文檔,則應該返回 404 Not Found,如果您不被允許訪問相關內容,則應該返回 403 Forbidden

在第一個狀態行之後,響應頭跟隨;它們提供了有關返回內容的更多信息,例如它 Content-type

接下來是一個空行。它標誌著不再有響應頭的事實。超過該行的所有內容都是其請求的文檔的內容。所以在上面的例子中, <!DOCTYPE html> 是SuperUser主頁的第一行(HTML文檔)。如果我要求下載文檔,則可能是一些亂碼,因為大多數文檔格式在沒有事先處理的情況下是不可讀的。

回到標題。對我們來說最有趣的是最後一個, Content-Length。它通知瀏覽器在空行之後應該預期多少字節數據,所以基本上它是以字節表示的文檔大小。此標頭不是必需的,服務器可以省略。有時無法預測文檔大小(例如,文檔是在運行時生成的),有時懶惰的程序員不包含它(在驅動程序下載站點上很常見),有時網站是由不知道的新手創建的這樣的標題。

無論如何,無論原因是什麼,標題都可能丟失。在這種情況下,瀏覽器不知道服務器將要發送多少數據,因此將文檔大小顯示為 未知,等待服務器關閉連接。這就是未知文檔大小的原因。


110
2017-07-09 07:51



一個非常非常小的注意事項:瀏覽器支持除HTTP之外的協議。但是其他協議現在很少見,並且基本上相同的概念適用於其他協議,即使細節不同。 - Robert Fisher
@RobertFisher FTP是一種罕見的協議? :p - Thomas
@Thomas這是我最近的經歷。我記得在瀏覽器中看到一個ftp URL已經好幾年了。幾年前我直接使用ftp而不是瀏覽器工作(幾乎完全上傳),但這些任務現在由scp處理。我今天唯一使用ftp的是將內容上傳到極簡主義的網絡主機。當然,YMMV。 ^ _ ^ - Robert Fisher
這正是那種讓我愛上這個網站的答案。我如何授予它賞金? - That Brazilian Guy
@ ruda.almeida你不同意,你可以在meta.superuser.com上發布它,它將被討論,也許有人會重新打開這個問題。 - gronostaj


HTTP Content-Length 在某些情況下,header是可選的,因此它可能不會隨文件一起傳輸;當套接字關閉時,將發出文件的結尾信號。


52
2017-07-09 05:52



確切地說,HTTP 1.0通過在每個文檔之後關閉套接字來定義內容長度。為了兼容性,HTTP 1.1仍然支持此功能。但是HTTP 1.1允許重用多個文檔的連接 Content-Length 使用標題字段或傳輸文檔 Transfer-Encoding: chunked。後者允許動態生成內容並在生成內容時將其分段發送,並能夠發出文檔結束的信號。 - x4u


當內容(例如a .pdf 文檔或Excel工作表)是動態創建的,之前無法知道。在這種情況下,服務器無法向您發送下載的大小,並且瀏覽器無法顯示總大小。


3
2017-07-09 06:14



@alfo將不得不反對...如果我正在播放視頻,或者即使我正在流式傳輸任何不是固定大小的數據,如果重點是盡快將數據發送給用戶,我不會知道我開始傳輸時的大小 - Foon
@Alfo你可以創建像這樣的數據 .pdf 文件即時。只要數據寫得不合適,您就不知道大小,但您可以將ata發送到瀏覽器。我已經用Java完成了這項工作,並將Excel文件發送到瀏覽器,該文件即時生成。從瀏覽器方面看起來像下載,但從服務器端來看它是一個流媒體。所以有可能 流  .pdf 文件,即使你無法想像這一點。從瀏覽器看起來像沒有已知長度的下載。 - Uwe Plonus
@Alfo - 它只需要在最後一個數據包發送到客戶端之前完成創建。 - GalacticCowboy
@Alfo我從未接受過 視頻 蒸,但約 流 一般來說,也可以流式傳輸 .pdf 文件或Excel表格! - Uwe Plonus
@Alfo - 你有一個有效點,動態文件可以先在內存中完全創建,然後通過HTTP發送,並且很容易計算內容長度。但是,如果服務器正在發送許多大型動態創建的文件,這些文件將被分解成許多數據包,那麼服務器只需在計算它們時就開始發送這些塊是有意義的(而不是必須在內存中創建每個大文件然後發送)。 HTTP 1.1專門設計了 分塊傳輸編碼 以此目的。 - dr jimbob