我們都知道有JavaScript與CSS的壓縮實作,但對於HTML壓縮的實作在網路上比較少人在討論(而且有很多程式碼都是錯誤的),但其實說實在的,在現代JavaScript與CSS技術氾濫的推播下,大家對於JS、CSS的Minify都已經很有sense,可是反過頭來看,乘載的HTML母體,卻充斥著更多大量的空白、跳位、換行。不相信的話,下面這張微軟的網站原始碼截圖出來給你感受一下(這些換行與空白只是原始碼中的冰山一角)!
我這邊示範的範例還是以WebForm為主,如果你是採用MVC的話,可以考慮把類別掛在ActionFilter就可以了。
首先,打開你的Web.Config,找到system.webServer>modules,然後把等一下想要寫的IHttpModule類別用力插進去就對了。
<system.webServer> <modules runAllManagedModulesForAllRequests="true"> <add name="ChangeContent" type="Slashview.HttpResponseContent" /> </modules> </system.webServer>
沒有甚麼技術性,就是把IHttpModule叫出來掛上事件後,對Response.Filter再掛一個類別,接下來就交給ASP.NET的機制,等到最終要Flush前,ASP.NET會自動去Call你定義的Filter,等於對你的類別事件進行委派啦!
namespace Slashview { //實作IHttpModule來壓縮Http Response輸出的HTML字串 public class HttpResponseContent : System.Web.IHttpModule { public void Init(System.Web.HttpApplication oContext) { oContext.BeginRequest += OnBeginRequest; } public void OnBeginRequest(object sender, System.EventArgs e) { System.Web.HttpApplication oContext = (System.Web.HttpApplication)sender; //如果是ASPX程式就套用過濾器(這個時期抓不到在後期才改變ContentType的ASPX程式,例如:打圖、打JSON...,因此在此不做無意義ContentType的判斷) if (oContext.Request.CurrentExecutionFilePathExtension == ".aspx") { oContext.Response.Filter = new CompressHtmlFilter(oContext.Response); } } public void Dispose() { } //利用InnerClass建立一個過濾器(在裡面實作壓縮) private class CompressHtmlFilter : System.IO.MemoryStream { private System.Web.HttpResponse _oResponse; private readonly System.IO.Stream _oFilter; public CompressHtmlFilter(System.Web.HttpResponse oResponse) { _oResponse = oResponse; _oFilter = oResponse.Filter; } public override void Write(byte[] aryBuffer, int iOffset, int iCount) { //如果最終ContentType是text/html」才處理 if (_oResponse.ContentType == System.Web.MimeMapping.GetMimeMapping(".html")) { string cTemp = System.Text.Encoding.UTF8.GetString(aryBuffer); /* 以下條件均取代為空字串 * 換行符號:出現1次(含以上) * 註解區段:會排除中括號是因為header有時會出現BrowserHack,例如[if lt IE 9] */ cTemp = System.Text.RegularExpressions.Regex.Replace(cTemp, @"([\r\n]+)|(<!--[^\[\]]*?-->)", string.Empty); /* 以下條件均取代為一個空白 * 空白符號:出現2次(含以上) * 跳位符號:出現1次(含以上) */ //空白字元只要出現兩個(含以上),就會被取代為一個空白 cTemp = System.Text.RegularExpressions.Regex.Replace(cTemp, @"( {2,})|(\t+)", " "); //將運算過的字串輸出 _oFilter.Write(System.Text.Encoding.UTF8.GetBytes(cTemp), iOffset, System.Text.Encoding.UTF8.GetByteCount(cTemp)); } else //一律不處理丟出 { _oFilter.Write(aryBuffer, iOffset, iCount); } } } } }
程式寫完後,去重新整理你的aspx網頁,就可以看到你的HTML都被壓縮啦!
補充資料:附上Http Request(Http Module) Liftcycle生命週期,讓讀者可以有更透徹的認識。
延伸閱讀
修正HTTP Response Header中的Server屬性
使用ASP.NET的路由環境下,讓ASPX、ASHX等WebForm技術仍然可以繼續運作