天天看點

ASP.NET上傳大檔案的構想

前面研究了一下ASP.NET的程序模型,實際上就是為了“上傳大檔案”這個最終目的服務的。

大檔案上傳的可行性研究

網際網路的應用從狹義上,或許可以看成“Request-and-Response”的過程。Request指的是用戶端向伺服器送出請求,Response是指伺服器根據用戶端的請求而做出的回應。而Response都一個回應時間的問題,是以在大檔案上傳過程中失敗的可能性非常大,并且大多是逾時的問題。

可行性的另一方面考慮是指檔案上傳過程的操作。通過<input type="file" />上傳的檔案,在ASP.NET 1.1時代,上傳的檔案會被完全載入記憶體,再進行寫硬碟的操作。這就帶來一個很大的問題,記憶體的空間畢竟有限,如果上傳的檔案比較大,又或者同時上傳的人比較多,記憶體被耗盡,上傳自然會失敗。

實際上,最早在使用ASP經典上傳空間ASPUpload時,就有這樣的問題。使用者通常反應上傳超過100M的檔案,到最後(指上傳快結束時)會報錯,并且之前所做的努力也白費了。因為資源從記憶體中被釋放了。

需要知道的是,上傳協定本身并沒有規定伺服器本身應該怎麼來操作上傳的檔案。

ASP.NET 2.0時代,對檔案上傳的方式做了一些改進,啟用硬碟臨時檔案的門檻值(threshold)。該閥值是可配置。

<system.web>

  <httpRuntime maxRequestLength="4096" requestLengthDiskThreshold="256" />

</system.web>

以上預設值,規定了最大上傳檔案是4M,而當一個請求内容超過256K時就會啟用硬碟作為緩存。是以在ASP.NET 2.0中伺服器的記憶體不會因為用戶端的異常請求而耗盡。

大檔案上傳的友好性研究

友好性也展現在兩個方面。一是上傳的進度顯示和上傳過程遇到意外狀況的斷點續傳。

檔案的上傳都可以分塊進行。是以對于上傳進度的計算,一是在用戶端進行,通過對本地檔案大小和偏移量的計算,可以知道上傳請求中的檔案上傳進度,這與實際檔案上傳進度有偏差,但把進度計算轉嫁于用戶端,實作了高效率;另一種是在服務端進行,通過儲存在伺服器硬碟上的臨時檔案來計算偏移量,進而得知實際檔案上傳的進度,資料準确,但效率很低。每次都必須在檔案塊儲存之後,傳回目前已儲存檔案塊的容量值。

斷點續傳是一個在HTTP協定中,很少被采取的解決方案。最大的原因可能就是本地檔案操作權限的問題。網際網路的應用程式無法給<input type="file" />進行指派,是以每次意外狀況出現之後的再次上傳,使用者都不得不重新選擇之前上傳的同一個檔案。此時,新問題出現。如果确認先後兩次選擇的檔案是同一個檔案?

要規避安全問題的話,或許ActiveX控件是個不錯的選擇,但ActiveX是IE Only的。我們必須得考慮不斷增長的非IE使用者。

大檔案上傳的思考(ASP.NET)

 1、想要上傳大檔案,首先得繞開maxRequestLength的限制。而大檔案的定義,基本上就是不限制上傳檔案的大小;

2、想要繞開maxRequestLength的限制,就不能在用戶端簡單的通過Form把檔案以multipart/form-data方式POST出來,然後伺服器端接收、儲存;

3、大檔案上傳和進度條顯示的美好構想:在IIS将用戶端發送的内容發送到Asp.NET的Pipeline時,随着伺服器接收内容的同時,将檔案内容寫到伺服器磁盤中,然後在Asp.NET的管道中隻放入請求的對應的Form内容,同時提供伺服器接收進度顯示;

4、通過HttpModule,隻需要在最早的事件BeginRequest中,處理資料接收,就可以避開Asp.NET的最大請求長度限制;

5、斷點續傳的美好構想:在重新上傳檔案時,先從伺服器端讀出臨時檔案的大小(位元組數),然後再從該位元組數開始讀取本地檔案。