《ASP.NET本質論》大文件上傳

        在網站中,上傳文件到服務器是一個開發中常見的問題。在ASP.NET 2.0中,還提供了一個FileUpload控件,可以更加簡單地完成文件上傳的工作。但是,在上傳一個比較大的文件時,就會發現上傳文件失敗了。

-----文件上傳的規範
        通過瀏覽器上傳文件的標準是在RFC1867中定義的,RFC1867在HTTP協議的基礎上,爲input元素增加了type="file"的屬性,相應地,在form表單中使用這種input的時候,表單的method必須爲post方式,同時表單的enctype也必須設置爲multipart/form-data,如下圖所示:

<form method="post" action="Default.aspx" id="form1" enctype="multipart/form-data">
    <input type="file" name="FileUpload1" id="FileUpload1" />
    <input type="submit" name="Button1" value="Button" onclick ="uploadProgeress();" id="Button1" />
</form>

對瀏覽器來說,type屬性爲file的input元素將會顯示爲一個文本框和一個瀏覽文件的按鈕。
當選中文件後,提交表單的時候,被選中的文件將隨着此次請求發送到服務器。
表單的enctype屬性默認爲application/x-www-form-urlencoded。在這種方式下,參數之間通過&符號進行分隔,由於在上傳文件的時候,文件中也可能包含&符號,因此,不能使用默認的application/x-www-form-urlencoded方式,enctype必須設置爲multipart/form-data方式。
在multiparty/form-data方式下,HTTP Request也會有一些變化
首先,在請求頭的Content-Type中除了說明使用multiparty/form-data方式以外,增加了boundary的說明,boundary用來說明請求參數之間的分隔邊界,boundary中的數字字符區是隨機生成的。

以前的content-type頭如下:
content-type:application/x-www-form-urlencoded
改變後的content-type頭如下:
Content-Type: multipart/form-data;
boundary=---------------------------27870960

其中boundary的實際內容是由瀏覽器生成的,並不一定與上面相同。
其次,在請求的數據實體部分有了更多的變化。上傳文件內容也就是HTTP實體中的參數的一部分。參數之間通過boundary進行分割,HTTP的實體看起來將是下面的樣子:
Content-Type: multipart/form-data; boundary=---------------------------27870960128323


Content-Length: 415






-----------------------------27870960128323


Content-Disposition: form-data; name="FileUpload1"; filename="phone.txt"


Content-Type: text/plain






520630   805058548  ·¶Ã·Áá










520616   1192088350 лÕñ¶«






520618   649798842 Ðí¹úîÈ














593174 ÕÅ·É 116314032


-----------------------------27870960128323


Content-Disposition: form-data; name="Button1"






Button


-----------------------------27870960128323--


       通過boundary分隔的是可以可以被分成多個部分,每一部分又可以被分割成兩部分,說明部分和數據部分。說明部分和數據部分通過連續的兩個回車換行進行分隔。
對於普通參數來說,在說明部分將會包括name參數,說明參數的名字。數據部分將是參數的值。
對於上傳文件來說,在說明部分將會增加filename參數和Content-Type參數,在這兩個參數之後,通過連續的兩個回車換行分隔,一直到下一個分隔符志氣啊,即爲上傳文件的內容。

---------------ASP.NET中的文件上傳

        在ASP.NET 1.1中,文件上傳過程中將被全部保存在內存,對於大文件來說,會造成內存空間的過度使用,可能會招致惡意攻擊。爲了解決這個問題,ASP.NET在配置文件中提供了一個參數來控制上傳文件的尺寸,這個配置參數在system.web元素的子元素 httpRuntime元素中。maxRequestLength屬性用來設置允許的最大請求長度,這個參數的單位是KB(字節),默認情況下,參數的值爲4096,也就是最大能上傳大約4M大小的文件。如果希望上傳10M文件,可以對其進行修改爲 10240
         在ASP.NET 2.0之後,上傳的文件可以緩存到文件中,以減少對內存的消耗。httpRuntime元素提供了一個新的配置參數requestLengthDiskThreshold屬性,用來設置一個上傳文件尺寸的門檻,超過這個門檻後,請求的內容將會保存到文件中。這個參數的單位也是KB,默認爲80,這個值不應該超過 maxRequestLength參數。
       當請求的內容長度超過門檻的限值之後,請求的內容將會被保存到文件中,這個文件的位置由compilation配置元素的tempDirectory屬性指定。
       默認情況下,這個參數的值爲空串。臨時文件將會被保存在 %FrameworkInstallLocation%\TemporaryASP.NET 文件夾下。在Windows 7 下使用開發服務器的時候,臨時文件會保存在 c:Users\用戶名\AppData\Local\Temp\Temporary ASP.NET Files\下面
         在ASP.NET 2.0之後,知道ASP.NET 4.0 ,當使用 multipart/form-data方式的請求時,ASP.NET會將請求的Post數據通過System.Web.HttpRawUploadedContent進行管理,這是一個內部類,我們不能直接使用,HttpRequest的私有成員 _rawContent將指向這樣一個對象實例。
       雖然有了很大的改進,但是,對於大型文件的上傳,我們並不能掌握上傳的進度,在AJAX中,就難以顯示一個動態的上傳進度條,不能提供給用戶一個友好的上傳進程反饋。我們可以自定義一個文件上傳的管理器來完成這個功能。

文件上傳的解決方案
       在ASP.NET中,瀏覽器的請求數據到達ASP.NET網站後,被包裝爲一個內部的對象HttpWorkerRequest,從客戶端發送到服務器的數據在內部通過這個對象來讀取,HttpRequest提高哦你過了好怎對請求數據的包裝,從ASP.NET 2.0開始,在上傳文件過程中,上傳的數據通過HttpRawUploadedContent對象來表示,這是HttpRequest的一個內部成員,可以通過HttpRequest還沒有讀取上傳文件的情況下,接管ASP.NET對請求參數的讀取過程,自定義針對文件上傳的處理,實現上傳文件的管理。
      對於其他的Post數據,可以通過反射來構建一個模擬的HttpRawUplaodedContent對象實例,提供給HttpRequest使用,保證在候機的處理中正常獲取表單數據,

-------------------通過HttpModule接管請求參數
       在文件上傳過程中,ASP.NET架構的底層會肚臍HTTP請求中的信息,在系統內部創建一個類型爲HttpRawUploadedContent的對象來表示請求參數,這個對象被HttpRequest對象所使用。
      爲了接管HttpRequest對請求參數的處理,我們註冊HttpApplication的最早的事件BeginRequest,然後將讀取的數據保存到一個自定義的對象中。爲了能後在後繼的處理過程中繼續通過HttpRequest來訪問請求數據,我們創建一個僞造的HttpRawUploadedContent提供給HttpRequest對象使用。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章