务实直接上代码:

1. 重写FilterModule.cs

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using System.Text.RegularExpressions;
using System.IO.Compression; namespace Compress.FilterModule
{
public class FilterModule : IHttpModule
{
public void Dispose()
{
//
} /// <summary>
/// Init method is only used to register the desired event
/// </summary>
/// <param name="context"></param>
public void Init(HttpApplication context)
{
context.BeginRequest += new EventHandler(context_BeginRequest);
//context.EndRequest += new EventHandler(context_EndRequest);
//context.PostRequestHandlerExecute += new EventHandler(context_PostRequestHandlerExecute);
} /// <summary>
/// Handles the BeginRequest event of the context control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
void context_BeginRequest(object sender, EventArgs e)
{
HttpApplication app = sender as HttpApplication;
HttpContext context = app.Context;
if (context.CurrentHandler is System.Web.UI.Page)
{
bool isPage = context.CurrentHandler.IsReusable;
}
if (app.Request.RawUrl.Contains(".aspx") || app.Request.RawUrl.EndsWith("/"))
{
// HttpContext context = app.Context;
HttpRequest request = context.Request;
string acceptEncoding = request.Headers["Accept-Encoding"];
HttpResponse response = context.Response;
if (!string.IsNullOrEmpty(acceptEncoding))
{
acceptEncoding = acceptEncoding.ToUpperInvariant();
if (acceptEncoding.Contains("GZIP"))
{
//var straem = new GZipStream(response.Filter, CompressionMode.Compress);
response.Filter = new CompressWhitespaceFilter(response.Filter, CompressOptions.GZip);
response.AppendHeader("Content-encoding", "gzip");
}
else if (acceptEncoding.Contains("DEFLATE"))
{
response.Filter = new CompressWhitespaceFilter(context.Response.Filter, CompressOptions.Deflate);
response.AppendHeader("Content-encoding", "deflate");
}
}
response.Cache.VaryByHeaders["Accept-Encoding"] = true;
}
} // Test
//void context_BeginRequest(object sender, EventArgs e)
//{
// HttpApplication application = (HttpApplication)sender;
// HttpContext context = application.Context;
// context.Response.ContentType = "text/html";
// context.Response.Charset = "GB2312";
// context.Response.ContentEncoding = Encoding.Default;
// context.Response.Write("<h1 style='color:#00f'>Treatment from HttpModule,Begin...</h1><hr>");
//} // Test
//void context_EndRequest(object sender, EventArgs e)
//{
// HttpApplication application = (HttpApplication)sender;
// HttpContext context = application.Context;
// context.Response.ContentType = "text/html";
// context.Response.Charset = "GB2312";
// context.Response.ContentEncoding = Encoding.Default;
// context.Response.Write("<hr><h1 style='color:#f00'>Treatment from HttpModule,End...</h1>");
//} }
}

2. 处理压缩和匹配自定义过滤 CompressWhitespaceFilter.cs

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using System.IO.Compression; namespace Compress.ModuleDemo
{
public enum CompressOptions
{
GZip,
Deflate,
None
} public class CompressWhitespaceFilter : Stream
{
StringBuilder responseHtml;
const string _cssPattern = "(?<HTML><link[^>]*href\\s*=\\s*[\\\"\\']?(?<HRef>[^\"'>\\s]*)[\\\"\\']?[^>]*>)";
const string _jsPattern = "(?<HTML><script[^>]*src\\s*=\\s*[\\\"\\']?(?<SRC>[^\"'>\\s]*)[\\\"\\']?[^>]*></script>)"; private HttpApplication app;
public HttpApplication App
{
get { return app; }
set { app = value; }
} private GZipStream _contentGZip;
private DeflateStream _content_Deflate;
private Stream _content;
private CompressOptions _options;
private bool disposed = false; private CompressWhitespaceFilter() { }
public CompressWhitespaceFilter(Stream content, CompressOptions options)
{ responseHtml = new StringBuilder();
if (options == CompressOptions.GZip)
{
this._contentGZip = new GZipStream(content, CompressionMode.Compress, true);
this._content = this._contentGZip;
}
else if (options == CompressOptions.Deflate)
{
this._content_Deflate = new DeflateStream(content, CompressionMode.Compress, true);
this._content = this._content_Deflate;
}
else
{
this._content = content;
}
this._options = options;
} public override bool CanRead
{
get { return this._content.CanRead; }
} public override bool CanSeek
{
get { return this._content.CanSeek; }
} public override bool CanWrite
{
get { return this._content.CanWrite; }
} /// <summary>
/// When overriding in a derived class, all buffers of the stream are cleared and all buffer data is written to the underlying device
/// </summary>
public override void Flush()
{
this._content.Flush();
//Test
//this._content.Dispose();
//this._contentGZip.Dispose();
} /// <summary>
/// 重写Dispose方法,释放派生类自己的资源,并且调用基类的Dispose方法
/// 使Gzip把缓存中余下的内容全部写入MemoryStream中,因为只有在Gzip流释放之后才能去承载对象中读取数据或判断数据大小
/// </summary>
/// <param name="disposing"></param>
protected override void Dispose(bool disposing)
{
if (!this.disposed)
{
try
{
if (disposing)
{
// Release the managed resources you added in this derived class here.
//xx.Dispose();
} // Release the native unmanaged resources you added in this derived class here.
// xx.Close() //if (_contentGZip != null)
// _contentGZip.Close(); //if (_content_Deflate != null)
// _content_Deflate.Close(); this._content.Close();
this.disposed = true;
}
finally
{
// Call Dispose on your base class.
base.Dispose(disposing);
}
}
} public override long Length
{
get { return this._content.Length; }
} public override long Position
{
get
{
return this._content.Position;
}
set
{
this._content.Position = value;
}
} public override int Read(byte[] buffer, int offset, int count)
{
return this._content.Read(buffer, offset, count);
} public override long Seek(long offset, SeekOrigin origin)
{
return this._content.Seek(offset, origin);
} public override void SetLength(long value)
{
this._content.SetLength(value);
} public override void Write(byte[] buffer, int offset, int count)
{
byte[] data = new byte[count + ];
Buffer.BlockCopy(buffer, offset, data, , count);
string s = System.Text.Encoding.UTF8.GetString(data);
s = Regex.Replace(s, "^\\s*", string.Empty, RegexOptions.Compiled | RegexOptions.Multiline);
s = Regex.Replace(s, "\\r\\n", string.Empty, RegexOptions.Compiled | RegexOptions.Multiline);
s = Regex.Replace(s, "<!--*.*?-->", string.Empty, RegexOptions.Compiled | RegexOptions.Multiline);
byte[] outdata = System.Text.Encoding.UTF8.GetBytes(s);
this._content.Write(outdata, , outdata.GetLength());
} /// <summary>
/// Replcase stylesheet links with ones pointing to HttpHandlers that compress and cache the css
/// </summary>
/// <param name="html"></param>
/// <returns></returns>
public string ReplaceCss(string html)
{
// create a list of the stylesheets
List<string> stylesheets = new List<string>();
// create a dictionary used for combining css in the same directory
Dictionary<string, List<string>> css = new Dictionary<string, List<string>>(); // create a base uri which will be used to get the uris to the css
Uri baseUri = new Uri(app.Request.Url.AbsoluteUri); // loop through each match
foreach (Match match in Regex.Matches(html, _cssPattern, RegexOptions.IgnoreCase))
{
// this is the enire match and will be used to replace the link
string linkHtml = match.Groups[].Value;
// this is the href of the link
string href = match.Groups[].Value; // get a uri from the base uri, this will resolve any relative and absolute links
Uri uri = new Uri(baseUri, href);
string file = "";
// check to see if it is a link to a local file
if (uri.Host == baseUri.Host)
{
// check to see if it is local to the application
if (uri.AbsolutePath.ToLower().StartsWith(app.Context.Request.ApplicationPath.ToLower()))
{
// this combines css files in the same directory into one file (actual combining done in HttpHandler)
int index = uri.AbsolutePath.LastIndexOf("/");
string path = uri.AbsolutePath.Substring(, index + );
file = uri.AbsolutePath.Substring(index + );
if (!css.ContainsKey(path))
css.Add(path, new List<string>());
css[path].Add(file + (href.Contains("?") ? href.Substring(href.IndexOf("?")) : ""));
// replace the origianl links with blanks
html = html.Replace(linkHtml, "");
// continue to next link
continue;
}
else
file = uri.AbsolutePath + uri.Query;
}
else
file = uri.AbsoluteUri;
string newLinkHtml = linkHtml.Replace(href, "css.axd?files=" + file); // just replace the link with the new link
html = html.Replace(linkHtml, newLinkHtml);
} StringBuilder link = new StringBuilder();
link.AppendLine("");
foreach (string key in css.Keys)
{
link.AppendLine(string.Format("<link href='{0}css.axd?files={1}' type='text/css' rel='stylesheet' />", key, string.Join(",", css[key].ToArray()))); } // find the head tag and insert css in the head tag
int x = html.IndexOf("<head");
int num = ;
if (x > -)
{
num = html.Substring(x).IndexOf(">");
html = html.Insert(x + num + , link.ToString());
}
return html;
} /// <summary>
/// Replcase javascript links with ones pointing to HttpHandlers that compress and cache the javascript
/// </summary>
/// <param name="html"></param>
/// <returns></returns>
public string ReplaceJS(string html)
{
// if the javascript is in the head section of the html, then try to combine the javascript into one
int start, end;
if (html.Contains("<head") && html.Contains("</head>"))
{
start = html.IndexOf("<head");
end = html.IndexOf("</head>");
string head = html.Substring(start, end - start); head = ReplaceJSInHead(head); html = html.Substring(, start) + head + html.Substring(end);
} // javascript that is referenced in the body is usually used to write content to the page via javascript,
// we don't want to combine these and place them in the header since it would cause problems
// or it is a WebResource.axd or ScriptResource.axd
if (html.Contains("<body") && html.Contains("</body>"))
{
start = html.IndexOf("<body");
end = html.IndexOf("</body>");
string head = html.Substring(start, end - start); head = ReplaceJSInBody(head); html = html.Substring(, start) + head + html.Substring(end);
} return html;
} /// <summary>
/// Replaces the js in the head tag. (see ReplaceCss for comments)
/// </summary>
/// <param name="html"></param>
/// <returns></returns>
public string ReplaceJSInHead(string html)
{
List<string> javascript = new List<string>();
Dictionary<string, List<string>> js = new Dictionary<string, List<string>>(); Uri baseUri = new Uri(app.Request.Url.AbsoluteUri);
foreach (Match match in Regex.Matches(html, _jsPattern, RegexOptions.IgnoreCase))
{
string linkHtml = match.Groups[].Value;
string src = match.Groups[].Value; Uri uri = new Uri(baseUri, src);
if (!Path.GetExtension(uri.AbsolutePath).Equals("js") && uri.AbsolutePath.Contains("WebResource.axd"))
continue;
if (uri.Host == baseUri.Host)
{
if (uri.AbsolutePath.ToLower().StartsWith(app.Context.Request.ApplicationPath.ToLower()))
{
int index = uri.AbsolutePath.LastIndexOf("/");
string path = uri.AbsolutePath.Substring(, index + );
string file = uri.AbsolutePath.Substring(index + );
if (!js.ContainsKey(path))
js.Add(path, new List<string>());
js[path].Add(file + (src.Contains("?") ? src.Substring(src.IndexOf("?")) : ""));
}
else
javascript.Add(uri.AbsolutePath + uri.Query); }
else
javascript.Add(uri.AbsoluteUri);
html = html.Replace(linkHtml, "");
} int x = html.IndexOf("<head");
int num = html.Substring(x).IndexOf(">");
string link = ""; foreach (string key in js.Keys)
{
link = string.Format("<script src='{0}js.axd?files={1}' type='text/javascript' ></script>", key, string.Join(",", js[key].ToArray()));
html = html.Insert(x + num + , link + Environment.NewLine); }
if (javascript.Count > )
{
link = string.Format("<script src='js.axd?files={0}' type='text/javascript' /></script>", string.Join(",", javascript.ToArray()));
html = html.Insert(x + num + , link + Environment.NewLine);
}
return html;
} /// <summary>
/// Replaces the js in the body. (see ReplaceCss for comments)
/// </summary>
/// <param name="html"></param>
/// <returns></returns>
public string ReplaceJSInBody(string html)
{
Uri baseUri = new Uri(app.Request.Url.AbsoluteUri);
foreach (Match match in Regex.Matches(html, _jsPattern, RegexOptions.IgnoreCase))
{
string linkHtml = match.Groups[].Value;
string src = match.Groups[].Value; Uri uri = new Uri(baseUri, src);
if (!uri.AbsolutePath.EndsWith(".js") && !uri.AbsolutePath.Contains("WebResource.axd"))
continue;
string file = "";
string path = "";
if (uri.Host == baseUri.Host)
{
if (uri.AbsolutePath.ToLower().StartsWith(app.Context.Request.ApplicationPath.ToLower()))
{
int index = uri.AbsolutePath.LastIndexOf("/");
path = uri.AbsolutePath.Substring(, index + );
file = uri.AbsolutePath.Substring(index + ) + (src.Contains("?") ? src.Substring(src.IndexOf("?")) : "");
}
else
file = uri.AbsolutePath + uri.Query;
}
else
file = uri.AbsoluteUri;
string newLinkHtml = linkHtml.Replace(src, path + "js.axd?files=" + file);
html = html.Replace(linkHtml, newLinkHtml);
}
return html;
} }
}

在这里需要注意的是对GZIP 的释放,否则流数据会读取不到:

         /// <summary>
/// 重写Dispose方法,释放派生类自己的资源,并且调用基类的Dispose方法
/// 使Gzip把缓存中余下的内容全部写入MemoryStream中,因为只有在Gzip流释放之后才能去承载对象中读取数据或判断数据大小
/// </summary>
/// <param name="disposing"></param>
protected override void Dispose(bool disposing)
{
if (!this.disposed)
{
try
{
if (disposing)
{
// Release the managed resources you added in this derived class here.
//xx.Dispose();
} // Release the native unmanaged resources you added in this derived class here.
// xx.Close() //if (_contentGZip != null)
// _contentGZip.Close(); //if (_content_Deflate != null)
// _content_Deflate.Close(); this._content.Close();
this.disposed = true;
}
finally
{
// Call Dispose on your base class.
base.Dispose(disposing);
}
}
}

对于C#非托管资源释放(Finalize/Dispose)方法理解:

http://www.cnblogs.com/lzhdim/archive/2009/11/04/1595845.html

ASP.Net 重写IHttpModule 来拦截 HttpApplication 实现HTML资源压缩和空白过滤的更多相关文章

  1. 使用rewrite 让php 实现类似asp.net 的IHttpModule 进行带参数js文件的参数获取

    asp.net 的IHttpModule 接口具有很大的作用,我们可以使用实现的模块进行全局的控制,但是在学习php 的过程中也想实现类似的功能,查找php 的文档,自己没有找到, 但是我们大家应该知 ...

  2. asp.net core 使用中间件拦截请求和返回数据,并对数据进行加密解密。

    原文:asp.net core 使用中间件拦截请求和返回数据,并对数据进行加密解密. GitHub demo https://github.com/zhanglilong23/Asp.NetCore. ...

  3. IIS7 ASP.NET 未被授权访问所请求的资源

    IIS7 ASP.NET 未被授权访问所请求的资源 ASP.NET 未被授权访问所请求的资源.请考虑授予 ASP.NET 请求标识访问此资源的权限. ASP.NET 有一个在应用程序没有模拟时使用的基 ...

  4. ASP.NET 未被授权访问所请求的资源。请考虑授予 ASP.NET 请求标识访问此资源的权限

    开发了一个导入TXT文件的功能,执行过程中出错.提示:.....ASP.NET 未被授权访问所请求的资源.请考虑授予 ASP.NET 请求标识访问此资源的权限.ASP.NET 有一个在应用程序没有模拟 ...

  5. asp.net实现IHttpModule接口注意事项

    IHttpModule向实现类提供模块初始化和处置事件. IHttpModule包含兩個方法: public void Init(HttpApplication context);public voi ...

  6. asp.net 使用IHttpModule 做权限检查 登录超时检查(转)

    IHttpModule 权限 检查 登录超时检查 这样就不需要每个页面都做一次检查 也不需要继承任何父类. using System;using System.Collections.Generic; ...

  7. ASP.NET MVC 异常Exception拦截

    一.前言 由于客户端的环境不一致,有可能会造成我们预计不到的异常错误,所以在项目中,友好的异常信息提示,是非常重要的.在asp.net mvc中实现异常属性拦截也非常简单,只需要继承另一个类(Syst ...

  8. ASP.NET MVC 异常Exception拦截器Fillter

    异常信息的处理在程序中非常重要, 在asp.net mvc中提供异常属性拦截器进行对异常信息的处理,异常拦截器也没有什么的,只是写一个类,继承另一个类(System.Web.Mvc.FilterAtt ...

  9. ASP.NET MVC的Action拦截器(过滤器)ActionFilter

    有时项目要进行客户端请求(action)进行拦截(过滤)验证等业务,可以使用拦截器进行实现,所谓的action拦截器也没有什么的,只是写一个类,继承另一个类(System.Web.Mvc.Filter ...

随机推荐

  1. 简体中文 — ANSI Common Lisp 中文版

    简体中文 - ANSI Common Lisp 中文版 简体中文¶

  2. html中的table在android端显示

    转载请注明出处:http://blog.csdn.net/u012338845/article/details/46773245 開始都是用Html.fromHtml(source).来显示html的 ...

  3. js错误 SyntaxError: missing : after property id

    在用jquery的post方法时 $.post('adminCheckTpmisPlans.do',{'test',str},function(f){ ... }) 报如下错误 SyntaxError ...

  4. poj1639 Picnic Planning 最小度数限制生成树

    题意:若干个人开车要去park聚会,可是park能停的车是有限的,为k.所以这些人要通过先开车到其它人家中,停车,然后拼车去聚会.另外,车的容量是无限的,他们家停车位也是无限的. 求开车总行程最短. ...

  5. 执行命令行并等待完成(使用WaitForSingleObject达到目的)

    function TDMDb.WaitExeFinish(const sCmdName: string):boolean; var StartupInfo: TStartupInfo; Process ...

  6. [Android学习笔记]组合控件的使用

    组合控件的使用 开发过程中,多个UI控件需要协同工作,相互交互之后,才可完成一个完整的业务需求,此时可把这些控件封装成为一个整体,相互之间的交互逻辑封装其中,外部调用可无需关心内部逻辑,只需获取处理后 ...

  7. groovy : 正則表達式

    groovy 正則表達式 企图模仿Perl 的语法,结果是我试用后.发现没法提取匹配的字符串. 还是直接引用 java.util.regex  负责对字符序列进行正則表達式匹配 先转载水木清华上的样例 ...

  8. liunx清理磁盘du -h --max-depth=1 /data/*

    liunx清理磁盘du -h --max-depth=1 /data/*

  9. 日期格式化标签<fmt:formatDate>&<fmt:setTimeZone>时区标签的使用demo

    日期格式化标签<fmt:formatDate>&<fmt:setTimeZone>时区标签的使用demo <%@ page contentType="t ...

  10. HDU 4028 The time of a day STL 模拟题

    暴力出奇迹.. #include<stdio.h> #include<iostream> #include<algorithm> #include<vecto ...