Asp.net

如何在 ASP.NET 響應中傳遞大文件?

  • March 7, 2012

我不是在尋找從數據庫中流式傳輸文件內容的任何替代方案,實際上我在尋找問題的根源,這是執行文件直到 IIS 6,我們在經典模式下執行我們的應用程序,現在我們將 IIS 升級到 7,我們是在管道模式下執行應用程序池,這個問題就開始了。

我有一個處理程序,我必須將大文件傳遞給客戶請求。我面臨以下問題,

文件的平均大小為 4 到 100 MB,所以讓我們考慮 80MB 文件下載的情況。

緩沖開啟,慢啟動

Response.BufferOutput = True;

這導致文件的啟動非常緩慢,因為使用者下載甚至進度條直到幾秒鐘才會出現,通常是 3 到 20 秒,背後的原因是,IIS 先讀取整個文件,確定內容長度,然後開始文件傳輸. 文件正在影片播放器中播放,執行速度非常慢,但 iPad 只先下載文件的一小部分,因此執行速度很快。

緩衝關閉,無內容長度,快速啟動,無進度

Reponse.BufferOutput = False;

這導致立即啟動,但是終端客戶端(典型的瀏覽器,如 Chrome)不知道 Content-Length,因為 IIS 也不知道,所以它不顯示進度,而是說 X KB 已下載。

緩衝關閉、手動內容長度、快速啟動、進度和協議違規

Response.BufferOutput = False;
Response.AddHeader("Content-Length", file.Length);

這會導致在 Chrome 等中正確立即下載文件,但是在某些情況下,IIS 處理程序會導致“遠端客戶端關閉連接”錯誤(這種情況非常頻繁),而其他 WebClient 會導致協議衝突。這發生在所有請求中的 5% 到 10%,而不是每個請求。

我想正在發生的事情是,當我們不進行緩衝時,IIS 不會發送任何稱為 100 continue 的內容,並且客戶端可能會斷開連接而不期望任何輸出。但是,從源讀取文件可能需要更長的時間,但在客戶端我增加了超時但似乎 IIS 超時並且無法控制。

無論如何我可以強制 Response 發送 100 continue 並且不讓任何人關閉連接嗎?

更新

我在 Firefox/Chrome 中發現了以下標頭,對於協議違規或錯誤標頭,這裡似乎沒有什麼不尋常的。

Access-Control-Allow-Headers:*
Access-Control-Allow-Methods:POST, GET, OPTIONS
Access-Control-Allow-Origin:*
Access-Control-Max-Age:1728000
Cache-Control:private
Content-Disposition:attachment; filename="24.jpg"
Content-Length:22355
Content-Type:image/pjpeg
Date:Wed, 07 Mar 2012 13:40:26 GMT
Server:Microsoft-IIS/7.5
X-AspNet-Version:4.0.30319
X-Powered-By:ASP.NET

更新 2

Turning Recycling 仍然沒有提供太多,但我已將 MaxWorkerProcess 增加到 8,現在我得到的錯誤數量比以前少了。

但平均而言,在一秒鐘內的 200 個請求中,有 2 到 10 個請求失敗……,而且幾乎每隔幾秒就會發生這種情況。

更新 3

繼續 5% 的請求因“伺服器違反協議。Section=ResponseStatusLine”而失敗,我有另一個程序從使用 WebClient 的網路伺服器下載內容,平均每秒出現 4-5 次此錯誤有 5% 的請求失敗。有沒有辦法追踪 WebClient 失敗?

重新定義的問題

收到零字節文件

IIS 出於某種原因關閉了連接,在 WebConfig 的客戶端,我收到 0 字節的文件不是零字節,我們進行 SHA1 雜湊檢查,這告訴我們在 IIS Web 伺服器中,沒有記錄錯誤。

這是我的錯誤,它在我們使用實體框架時得到了解決,它正在讀取臟(未送出的行),因為讀取不在事務範圍內,將它放在事務範圍內已經解決了這個問題。

引發協議違反異常

WebClient 拋出 WebException 說“伺服器違反了協議。Section=ResponseStatusLine。

我知道我可以啟用不安全的標頭解析,但這不是重點,當它是我的 HTTP 處理程序發送正確的標頭時,不知道為什麼 IIS 發送任何額外的東西(在 firefox 和 chrome 上檢查,沒有什麼異常),這只會發生 2 % 的時間。

更新 4

發現 sc-win32 64 錯誤,我在某處讀到 MinBytesPerSecond 的 WebLimits 必須從 240 更改為 0,但一切仍然相同。但是我注意到,每當 IIS 記錄 64 sc-win32 錯誤時,IIS 將 HTTP 狀態記錄為 200,但有一些錯誤。現在我無法打開 200 的失敗跟踪日誌記錄,因為它會導致大量文件。

上述兩個問題都通過增加 MinBytesPerSecond 和禁用會話來解決,我添加了詳細的答案來總結每一點。

雖然在 IIS 中傳遞大文件的正確方法是以下選項,

  1. 在 WebLimits 中將 MinBytesPerSecond 設置為零(這肯定會有助於提高性能,因為 IIS 選擇關閉持有 KeepAlive 連接的客戶端並進行較小的傳輸)
  2. Allocate More Worker Process to Application Pool,我設置為 8,現在只有當你的伺服器分發更大的文件時才應該這樣做。這肯定會導致其他站點的執行速度變慢,但這將確保更好的傳遞。我們設置為 8,因為該伺服器只有一個網站,它只提供大量文件。
  3. 關閉應用程序池回收
  4. 關閉會話
  5. 保持緩沖開啟
  6. 在以下每個步驟之前,檢查 Response.IsClientConnected 是否為真,否則放棄並且不發送任何內容。
  7. 發送文件前設置 Content-Length
  8. 刷新響應
  9. 寫入輸出流,並定期刷新

引用自:https://stackoverflow.com/questions/9600856