上一篇有提到利用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>标签,所以就放弃了这种方法。因为项目时间关系,最后偷了一点懒,在后台管理中添加一个“重新发布”的功能,直接将之前生成的静态页面全部删除掉。