2013-11-27 87 views
8

我想擴展我的REST服務(使用WCF/webHttpBinding構建),以便客戶端可以上傳經過壓縮的數據。我不確定要達到這個目的的最佳方式,但是我認爲通過添加一個HTTP模塊可以相當容易,該模塊將在傳入請求的Content-Encoding設置爲gzip時解壓縮數據。我可以使用HTTP模塊更改傳入HTTP請求的內容嗎?

所以我創建了一個類從IHttpModule的導出具有以下實現:

private void OnBeginRequest(object sender, EventArgs e) 
    { 
    var app = (HttpApplication) sender; 
    var context = app.Context; 

    var contentEncoding = context.Request.Headers["Content-Encoding"]; 

    if (contentEncoding == "gzip") 
    { 
     // some debug code: 
     var decompressedStream = new GZipStream(context.Request.InputStream, CompressionMode.Decompress); 
     var memoryStream = new MemoryStream(); 
     decompressedStream.CopyTo(memoryStream); 
     memoryStream.Seek(0, SeekOrigin.Begin); 

     var streamReader = new StreamReader(memoryStream); 
     string msg = streamReader.ReadToEnd(); 

     context.Request.InputStream.Seek(0, SeekOrigin.Begin); 

     app.Request.Filter = //new TestFilterStream(app.Request.Filter); 
        new System.IO.Compression.GZipStream(
        app.Request.Filter, CompressionMode.Decompress); 
    } 

    } 

我看到的問題是,從來沒有實際執行GZipStream減壓。我已經確認傳入的數據實際上是gzip'd(msg變量包含正確的數據)。我也嘗試創建我自己的流類(TestFilterStream),並將其分配給app.Request.Filter,並且我確認了流類中沒有成員實際上由ASP.NET調用。所以看起來好像雖然可以指定一個過濾器,但實際上並未使用該過濾器。

是不是實際使用了HttpApplication.Request.Filter?

+0

你有沒有嘗試過設置'Request.Filter'沒有你的其他調試代碼?這可能是因爲您已經閱讀了請求流,因此它不會再應用此過濾器。 –

+0

我相信沒有理由相信Request.InputStream是可搜索的。它可能不是。嘗試刪除你的調試代碼,它可能是錯誤的(你可能必須關閉/沖洗decompressedStream才能真正寫入內存流)。 – Luaan

+1

請縮小這個問題的範圍,因爲從您的問題中不清楚實際發生的錯誤以及何時發生。問題實際上'GZipStream'沒有讀取底層流? 'contentEncoding'等於''gzip「','if'塊中的代碼被調用了嗎?您是否嘗試過記錄此方法被調用的時刻?你甚至確定你的模塊被加載了嗎? – CodeCaster

回答

0

我剛剛完成了一些測試,並且只要有請求主體和請求主體被http處理程序讀取,我的Request.Filter流就會被調用。我猜你使用PUT或POST,並肯定讀取請求正文,所以這應該不成問題。

我懷疑Knaģis的評論是正確的。您是否嘗試過沒有調試代碼?如果我深入研究HttpRequest源代碼,我會看到一個變量_rawContent正好寫入一次;同時應用請求過濾器。之後,_rawContent值只被緩存,並且從不更新(在添加過濾器時也不會重置)。

因此,通過在調試代碼中調用Request.InputStream,您肯定會阻止稍後應用您的過濾器。讀取Request.Headers集合是沒有問題的。

2

我嘗試設置請求過濾在兩個方面:

  1. 使用的HttpModule
  2. Application_BeginRequest()開始設置它(Global.asax中)

兩者具有相同的結果( VS2012 web項目+ IISExpress):

  • 如果沒有輸入數據(GET請求或類似的),t他Filter.Read不會被調用
  • 與實際數據的POST的情況下,執行過濾器和Web服務得到過濾後的數據
  • 即使我從Request.InputStream讀取設置過濾器前,我仍然得到過濾器從我的服務代碼觸發。

我沒有簡單的方法用Gzippet輸入進行測試,所以我沒有嘗試過,如果實際的過濾器工作。但是,我知道它正在被觸發,因爲我在嘗試查找輸入時從GZipStream得到一個錯誤。

也許你有其他的HttpModules或過濾器會破壞你的輸入或控制流?

This post提出類似你一個方法,而且還規定了以下內容,這可能會導致一些副作用(我的測試中沒有使用WCF):

「看來,這種做法引發的問題WCF,因爲WCF依賴於原始的Content-Length而不是解壓後獲得的值。「

0

你確定,應用程序本身應該打擾嗎? 通常這是根據主機(IIS)的配置處理的。所以,基本上,當你自己託管服務時,你只需要實現自定義的GZip支持。 你可以看看here

相關問題