2011-04-10 89 views
2

作爲一個實驗,我一直在嘗試創建一個IIS託管模塊來動態修改CSS文件。背後的故事是,所有的Web應用程序都保留一個共享和通用的版本號,我們附加到每個JS,CSS和圖像引用(HTML)中,並且我想修改CSS的實際內容以將版本號附加到圖像引用在CSS中。所以,舉例來說:自定義IIS模塊與gzip衝突

span.warning { background-image: url(warning-icon.png) } 

應該變成:

span.warning { background-image: url(warning-icon.png?123) } 

現在,我知道有很多不同的方法解決這個問題(和一些也許更好),但如果任何人都可以我想知道回答我關於我一直在玩的那個問題。

到目前爲止,我已經瞭解到託管的HTTP模塊不能直接修改響應流(我認爲),並且正確的方法是追加輸出過濾器來完成工作。我已經寫了下面的測試模塊:

public class HttpCSSModule : IHttpModule 
{ 

    public void Init(HttpApplication httpApplication) 
    { 
     httpApplication.BeginRequest += new EventHandler(
      (s, e) => AttachFilter((HttpApplication)s)); 
    } 

    private void AttachFilter(HttpApplication httpApplication) 
    { 
     HttpRequest httpRequest = httpApplication.Context.Request; 
     HttpResponse httpResponse = httpApplication.Context.Response; 
     if (httpRequest.Path.EndsWith(".css", StringComparison.CurrentCultureIgnoreCase)) 
     { 
      if (!string.IsNullOrEmpty(httpRequest.Url.Query)) 
      { 
       httpResponse.Filter = new CSSResponseStreamFilter(
        httpResponse.Filter, httpRequest.Url.Query); 
      } 
     } 
    } 

    public void Dispose() 
    { 
    } 

    private class CSSResponseStreamFilter : Stream 
    { 

     private Stream inner; 
     private string version; 
     private MemoryStream responseBuffer = new MemoryStream(); 

     public CSSResponseStreamFilter(Stream inner, string version) 
     { 
      this.inner = inner; 
      this.version = version; 
     } 

     public override void Close() 
     { 

      if (responseBuffer.Length != 0) 
      { 

       string stylesheet = Encoding.ASCII.GetString(
        responseBuffer.GetBuffer(), 0, (int)responseBuffer.Length); 

       // crude, just testing 
       string versionedStylesheet = stylesheet. 
        Replace(".png", ".png" + version). 
        Replace(".jpg", ".jpg" + version). 
        Replace(".gif", ".gif" + version); 

       byte[] outputBytes = Encoding.ASCII.GetBytes(versionedStylesheet); 
       innerStream.Write(outputBytes, 0, outputBytes.Length); 

      } 

      innerStream.Close(); 

     } 

     public override void Write(byte[] buffer, int offset, int count) 
     { 
      responseBuffer.Write(buffer, offset, count); 
     }    

     // other Stream members 

    } 

} 

模塊的工作原理,但並不總是和有件事情我不明白。最大的問題是當靜態文件壓縮打開時模塊不工作。當打開靜態文件壓縮時,對CSS文件的第一個請求就像往常一樣提供文件,但大概IIS會保留gzip版本,並且在任何子序列請求中,我的自定義流都會傳遞gzipped流。我還沒有找到檢測它的方法,但是可能存在更深層次的問題,因爲我實際上可能不瞭解IIS模塊應該如何工作。我的模塊應該對另一個模塊進行任何假設似乎是錯誤的,或者至少應該能夠定義它們在IIS配置中處理請求的順序。但是,這似乎沒有道理,因爲每個模塊都可以註冊以處理請求生命週期中的任何事件。

所以,如果我不得不重新制定我的想法,以更精緻的問題,這些問題將是:

我如何確保我的後處理/模塊稱爲文件由StaticFileModule模塊讀取和服務器之後,但在StaticCompressionModule之前?這個問題甚至有意義嗎?根據以上觀察,似乎有點矛盾。

+0

我有同樣的問題,我正在工作幾個小時來解決它。 :(你可以向我解釋一下你是如何解決這個問題的嗎? – iboware 2012-11-12 11:59:13

回答

2

有配置爲靜態文件壓縮包括特定的文件或MIME類型,我忘了哪一個。如果你想使用靜態壓縮,它只需要在實際上是靜態的文件上。你將用HttpModule重寫它們的事實意味着它們不再是靜態的。因此,您可以對這些文件類型使用動態壓縮,並且正如您所期望的,您需要確保您的動態壓縮將包含適當的MIME類型或文件擴展名。

+0

你是對的,它解決了這個問題,它實際上更符合邏輯(它不再是一個靜態文件),這也表明動態壓縮模塊(compdyn。 dll)和靜態壓縮模塊(compstat.dll)的區別在於它們處理的類型列表不同,它們必須以不同的方式集成到IIS管道中。 – 2011-04-10 04:42:09