天天看點

[轉]Asp.Net 上傳大檔案專題(1)--概述:上傳大檔案的難點

注意:以下紅色部分字型說明該内容引用于微軟的相關網站

因為要做一個視訊網站,是以需要提供使用者上傳視訊的功能。可是ASP.Net自帶的上傳控件隻能用于上傳小檔案,這顯然無法滿足需要。有些朋友可能要問了"為什麼需要用那個呀,直接FTP傳不就好了",是的,用FTP傳就友善了很多,但是FTP在使用者上傳後,無法對上傳的檔案進行線上編輯(比如格式轉換,添加到資料庫呀等),所有這些可以由網站自動完成的煩瑣的任務則都将交由管理人員來完成,這對于一個商業網站來說無疑增加了用人成本。而且這些重複的低腦力活的工作,看起來就和體力活沒什麼差別,這不又從另一個側面降低了我們這些IT人員的價值。扯遠了,言歸正傳,那MS為什麼要将這個上傳控件的能力限制這麼小呢?在MSDN以及微軟的其它網站上我們可以了解到:"web.config 配置檔案中的<httpRuntime> 節的 maxRequestLength 參數的預設值為 4096 (4 MB)。是以,預設情況下不能上傳大于這個值的檔案。這也是為了防止拒絕服務攻擊。"

可是,這樣一來就對我們上傳大檔案造成了麻煩。有些朋友可能發現既然限制上傳檔案大小是由于maxRequestLength 這個參數,那将這個值改大點不就OK了。的确,這樣做便可輕輕松松提高檔案上傳大小的限制,可是在"上傳過程中,ASP.NET 首先将整個檔案加載到記憶體中,然後使用者才可以将該檔案儲存到磁盤。"也就是說,如果使用者上傳的檔案大小為100M,那麼伺服器的記憶體中就要拿出100M來存放使用者上傳的檔案;如果是10個使用者在同時上傳,暫且不提并行性的問題,那10個使用者就要占用1000M的記憶體;如果是100、1000、甚至是幾萬個使用者呢?那麼,再大的記憶體都不夠你拿來提供使用者上傳的。

"另外,其他因素也會影響可以上載的最大檔案大小。這些因素包括可用記憶體、可用硬碟空間、處理器速度和目前網絡流量。對于上載的正常流量的檔案,Microsoft 建議您讓最大檔案大小介于 10 到 20 MB 之間。如果您很少上載檔案,則最大檔案大小可以為 100 MB。"

一個企業内部的視訊網站,估且算它的日流量為1000人次,那麼按照微軟的建議,所上傳的檔案大小應盡量控制在20M以内,可是這樣的大小還是很容易造成伺服器的癱瘓,綜合考慮後,我把大小控制在6M以内(為什麼在這個範圍,後面會有提到,提早告訴大家,是為了讓文章能連貫一點)。大家一定會奇怪“一般一部視訊大小都至少有個100~200M,小于6M的不多吧?” 是的,這個問題就是我們要解決的關鍵。

在解決這個問題前,大家必須先清楚一件事,我們這裡所說的檔案大小"6M","200M"指的是針對伺服器端而言呢,還是用戶端而言呢?正确的了解如下:200M是針對用戶端使用者而言的大小,一般情況下允許使用者上傳最大600M大小的檔案(這個600M是考慮到我伺服器的硬碟大小,大家可以靈活掌握,不過一般最好不要超過1G);6M則指的是伺服器端所能接收的檔案大小,這樣才能不讓伺服器的記憶體因為上傳檔案而被吞噬光。

那麼,現在我們就可以把問題轉化為:如何讓伺服器以小于6M的大小來接收使用者上傳的200M視訊的?

大家是不是看得有點暈,那我拿“奧運會門票出售的情況”來舉個例子。

這幾天是出售奧運會門票的最後一個階段,為了能在最後一階段買到門票,很多人都提早好幾天等在售票視窗前。我們假設有10W人需要門票(就好像使用者上傳200M的視訊),理想的情況自然是開10W個視窗來出售門票(這裡的視窗相當于伺服器可以接收的檔案大小,而10W則相當于我們将maxRequestLength等相關元素設定很大)。可是想一想就知道,這樣做是不可能的(原因自己想吧~)。那怎麼解決的呢?隻有将視窗數按照某種規則限制在一定數量(比如20個),然後想買票的人排隊買票。

相信通過這個例子,有些朋友可能已經想到了如何解決我們之前的問題了。辦法就是在伺服器端通過某種方法将請求分組接收。

這部分先寫到這了。

[補充] 很多朋友提出類似:"Asp.Net 2.0以上版本好像已經不全部放入記憶體"的意見,首先我很感謝大家的支援,發現自己的确對于這些内容掌握的還不夠深入。在大家的提醒下,查閱了一些相關資料,是以再做一個補充,以免其他人和我犯一樣的錯誤。以下内容摘自:随便說說:在ASP.NET應用程式中上傳檔案

對于某些伺服器端的技術,例如Spring Framework,或者早期ASP.NET 1.1時,為了供程式處理,都會将使用者上傳的内容完全載入記憶體,這的确會帶來問題。但是其實協定本身并沒有規定伺服器端應該使用何種方式來處理上傳的檔案。例如在現在的ASP.NET 2.0中就已經會在使用者上傳資料超過一定數量之後将其存在硬碟中的臨時檔案中,而這點對于開發人員完全透明,也就是說,開發人員可以像以前一樣進行資料流的處理。

ASP.NET 2.0啟用硬碟臨時檔案的門檻值(threshold)是可配置的:

<system.web>

<httpRuntime

maxRequestLength="Int32"

requestLengthDiskThreshold="Int32" />

</system.web>

  maxRequestLength自不必說,剛接觸ASP.NET的朋友總會發現上傳檔案不能超過4M,這就是因為maxRequestLength的大小預設為4096,這就限制着每個請求的大小不得超過4096KB。這麼做的目的是為了保護應用程式不受惡意請求的危害。當請求超過maxRequestLength之後,ASP.NET處理程式将不會處理該請求。這裡和ASP.NET抛出一個異常是不同的,這就是為什麼如果使用者上傳檔案太大,看到的并非是ASP.NET應用程式中指定的錯誤頁面(或者預設的),因為ASP.NET還沒有對這個請求進行處理。

requestLengthDiskThreshold就是剛才所提到的門檻值,其預設值為256,即一個請求内容超過256KB時就會啟用硬碟作為緩存。這個門檻值理論上和用戶端是否是在上傳内容無關,隻要用戶端發來的請求大于這個值即可。是以,在ASP.NET 2.0中伺服器的記憶體不會因為用戶端的異常請求而耗盡。

繼續閱讀