簡體   English   中英

將Response.Filter與Response.TransmitFile一起使用

[英]Using Response.Filter with Response.TransmitFile

我使用Response.Filter以便根據HTTP請求標頭Accept-Encoding實施流壓縮

這是重要的東西:

        if (AcceptEncoding.Contains("deflate") || AcceptEncoding == "*")
        {
             HttpApp.Response.Filter = new DeflateStream(PreviousOutputStream, CompressionMode.Compress);
             HttpApp.Response.AppendHeader("Content-Encoding", "deflate");
        }

總的來說,這是可以預期的。 但是,我處於在MVC控制器上使用ActionResult向用戶代理提供文件的情況下:

        Response.Clear();
        Response.Headers["Content-Type"] = contentType;
        Response.Headers["Content-Length"] = contentLength;

        if (Request.QueryString["dl"] == "1")
        {
            Response.Headers["Content-Disposition"] = "attachment; filename=" + fileInfo.Name;
        }

        Response.Flush();
        Response.TransmitFile(fileInfo.FullName);

更確切地說,該動作方法在Response.TransmitFile()調用之后返回new EmptyResult() 無需修改Response.Filter即可完全按預期工作。

在這種情況下,響應實體到達用戶代理時出現亂碼和難以理解。 FireFox的Poster插件顯示了空的實體或混亂的實體回來。

如果可以幫助,一定要尋找替代方法,因為在ASP.NET中手動進行壓縮並不有趣。 但是,如果您和我一樣頭腦堅定,我謹向您提出以下幾點。

首先:不要使用.NET的內置壓縮流類。 它們有問題,可以隨機截斷流末尾的字節。 我一直在使用DotNetZip並取得良好的效果: http ://dotnetzip.codeplex.com/

現在,一些附加說明:

  • Response.TransmitFile()不適用於響應過濾。
  • Response.BinaryWrite()不適用於響應過濾,因此您無法循環遍歷文件的內容並將其寫出。
  • Response.OutputStream不能與響應篩選一起使用,因此,您也無法遍歷文件的內容並以這種方式將其寫出。
  • Response.WriteFile()確實可以與響應篩選一起使用,但是它將整個文件加載到內存中並保存在那里,直到客戶端關閉連接為止,這不適用於大型文件。
  • 為了使事情變得更加有趣:如果將Response.BufferOutput設置為false,則響應過濾將停止工作。 (我只是花了幾個小時才弄清楚這一點)

顯然,圍繞響應過濾和寫入輸出流存在很多不同的問題。 通過使用Reflector和大量實驗,這是到目前為止我發現的最佳解決方案(“在各種情況下都能正常工作”)。

  1. 寫一個擴展Encoding的類,並將其稱為BinaryEncoding。 實現所有方法,以便它們正確復制字符和字節,但是當然要進行必要的類型轉換。

  2. 將Response.ContentEncoding設置為BinaryEncoding的實例(您可以非常成功地使用單例模式)。

  3. 使用FileStream打開文件。

  4. 創建一個new StreamReader(fileStream, new BinaryEncoding(), false) 該“ false”參數非常重要,它可以阻止StreamReader吃字節順序標記並覆蓋您的BinaryEncoding。

  5. 分配char []的緩沖區(我發現32KB是一個不錯的大小)。

然后,在循環中:

int n = StreamReader.Read(buffer, 0, buffer.Length);
Response.Write(buffer, 0, n);
Response.Flush();

直到n為0。

請注意:此方法會導致相當高的CPU使用率。 在100兆LAN上,單個客戶端以10MB /秒的速度下載時,一個內核上的CPU使用率將達到40-50%左右。 我希望我能找到一種更好的方法...如果我擁有Reflector Pro,也許可以找到一個。

如果您使用的是IIS7或IIS7.5,我建議您使用HTTP壓縮模塊,而不要自己動手使用。 這可能有助於解決問題。

http://technet.microsoft.com/zh-cn/library/cc771003(WS.10).aspx

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM