上一篇有提到利用IHttpModule和ResultFilter實現頁面靜態化功能。后來經過一些改動,將ResultFilter中要實現的功能全部轉移到IHttpModule中來實現
Asp.Net MVC頁面靜態化功能實現一:利用IHttpModule和ResultFilter
1、改動后的自定義IHttpModule實現代碼:
public class RouterHttpModule : IHttpModule { public void Init(HttpApplication application) { application.BeginRequest += this.Application_BeginRequest; //注冊事件 } private void Application_BeginRequest(Object source, EventArgs e) { HttpApplication application = (HttpApplication)source; HttpContext context = application.Context; string filePath = context.Request.FilePath; string fileExtension = VirtualPathUtility.GetExtension(filePath); //如果當前請求的不是資源文件、不是后台管理、請求中沒有表單信息、靜態頁面存在,則返回靜態頁面 if (string.IsNullOrEmpty(fileExtension) && !filePath.ToLower().StartsWith("/admin") && context.Request.Form.Count.Equals(0)) { string htmlPath = context.Request.HtmlFilePath(); if (File.Exists(htmlPath)) { context.Response.WriteFile(htmlPath); context.Response.End(); } context.Response.Filter = new HttpResponseFilterWrapper(context.Response.Filter, context); } } public void Dispose() { } }
這里只是在判斷靜態頁面文件是否存在之后加了這樣一段代碼:context.Response.Filter = new HttpResponseFilterWrapper(context.Response.Filter, context);
2、HttpResponseFilterWrapper的實現代碼
HttpResponseFilterWrapper的功能還跟以前一樣,保存Filter中返回給客戶端的html代碼到服務器硬盤上
public class HttpResponseFilterWrapper : Stream { private Stream inner; private HttpContext context; public HttpResponseFilterWrapper(System.IO.Stream s, HttpContext context) { this.inner = s; this.context = context; } public override bool CanRead { get { return inner.CanRead; } } public override bool CanSeek { get { return inner.CanSeek; } } public override bool CanWrite { get { return inner.CanWrite; } } public override void Flush() { inner.Flush(); } public override long Length { get { return inner.Length; } } public override long Position { get{ return inner.Position; } set{ inner.Position = value; } } public override int Read(byte[] buffer, int offset, int count) { return inner.Read(buffer, offset, count); } public override long Seek(long offset, System.IO.SeekOrigin origin) { return inner.Seek(offset, origin); } public override void SetLength(long value) { inner.SetLength(value); } public override void Write(byte[] buffer, int offset, int count) { if (!context.Response.StatusCode.Equals(200)) { return; } inner.Write(buffer, offset, count); //if (!context.HttpContext.Request.FilePath.ToLower().StartsWith("/admin")) //當前請求不是后台管理;並且返回客戶端是html才生成靜態頁面 if (!context.Request.FilePath.ToLower().StartsWith("/admin") && context.Response.ContentType.Equals("text/html")) { //靜態頁面保存路徑信息 string htmlPath = context.Request.HtmlFilePath(); string direcHtmlPath = Path.GetDirectoryName(htmlPath); if (!Directory.Exists(direcHtmlPath)) { Directory.CreateDirectory(direcHtmlPath); } //獲取返回客戶端的html代碼,並進行壓縮處理 string htmlCode = System.Text.Encoding.UTF8.GetString(buffer); string isZipHtml = WebConfigInfo.GetConfigValueByKey("IsCompressed"); //如果“IsCompressed”的值為空或0,則表示不壓縮 if (!string.IsNullOrEmpty(isZipHtml) && !isZipHtml.Equals(0)) { htmlCode = Regex.Replace(htmlCode, "^\\s*", string.Empty, RegexOptions.Compiled | RegexOptions.Multiline); htmlCode = Regex.Replace(htmlCode, "\\r\\n", string.Empty, RegexOptions.Compiled | RegexOptions.Multiline); htmlCode = Regex.Replace(htmlCode, "<!--*.*?-->", string.Empty, RegexOptions.Compiled | RegexOptions.Multiline); } //保存文件,這里不能用File.WriteAllText File.AppendAllText(htmlPath, htmlCode); } } }
3、確保靜態頁面數據的及時性
當在后台管理系統中,對某個欄目或某篇文章進行過增刪改的操作時,要同時保證靜態頁面中的數據與數據庫中的數據保持一致。
最初想到的實現方法是在靜態頁面中設定一個過期時間,但是公司所使用的框架中內容信息是通過異步加載進來的,所以保存的靜態頁面中不存<html><head><body>標簽,所以就放棄了這種方法。因為項目時間關系,最后偷了一點懶,在后台管理中添加一個“重新發布”的功能,直接將之前生成的靜態頁面全部刪除掉。