发布:2021/7/13 16:37:22作者:管理员 来源:本站 浏览次数:994
务实直接上代码:
1. 重写FilterModule.cs
复制代码
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.Threading.Tasks;
6 using System.Web;
7 using System.Text.RegularExpressions;
8 using System.IO.Compression;
9
10 namespace Compress.FilterModule
11 {
12 public class FilterModule : IHttpModule
13 {
14 public void Dispose()
15 {
16 //
17 }
18
19 /// <summary>
20 /// Init method is only used to register the desired event
21 /// </summary>
22 /// <param name="context"></param>
23 public void Init(HttpApplication context)
24 {
25 context.BeginRequest += new EventHandler(context_BeginRequest);
26 //context.EndRequest += new EventHandler(context_EndRequest);
27 //context.PostRequestHandlerExecute += new EventHandler(context_PostRequestHandlerExecute);
28 }
29
30
31 /// <summary>
32 /// Handles the BeginRequest event of the context control.
33 /// </summary>
34 /// <param name="sender">The source of the event.</param>
35 /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
36 void context_BeginRequest(object sender, EventArgs e)
37 {
38 HttpApplication app = sender as HttpApplication;
39 HttpContext context = app.Context;
40 if (context.CurrentHandler is System.Web.UI.Page)
41 {
42 bool isPage = context.CurrentHandler.IsReusable;
43 }
44 if (app.Request.RawUrl.Contains(".aspx") || app.Request.RawUrl.EndsWith("/"))
45 {
46 // HttpContext context = app.Context;
47 HttpRequest request = context.Request;
48 string acceptEncoding = request.Headers["Accept-Encoding"];
49 HttpResponse response = context.Response;
50 if (!string.IsNullOrEmpty(acceptEncoding))
51 {
52 acceptEncoding = acceptEncoding.ToUpperInvariant();
53 if (acceptEncoding.Contains("GZIP"))
54 {
55 //var straem = new GZipStream(response.Filter, CompressionMode.Compress);
56 response.Filter = new CompressWhitespaceFilter(response.Filter, CompressOptions.GZip);
57 response.AppendHeader("Content-encoding", "gzip");
58 }
59 else if (acceptEncoding.Contains("DEFLATE"))
60 {
61 response.Filter = new CompressWhitespaceFilter(context.Response.Filter, CompressOptions.Deflate);
62 response.AppendHeader("Content-encoding", "deflate");
63 }
64 }
65 response.Cache.VaryByHeaders["Accept-Encoding"] = true;
66 }
67 }
68
69 // Test
70 //void context_BeginRequest(object sender, EventArgs e)
71 //{
72 // HttpApplication application = (HttpApplication)sender;
73 // HttpContext context = application.Context;
74 // context.Response.ContentType = "text/html";
75 // context.Response.Charset = "GB2312";
76 // context.Response.ContentEncoding = Encoding.Default;
77 // context.Response.Write("<h1 style='color:#00f'>Treatment from HttpModule,Begin...</h1><hr>");
78 //}
79
80 // Test
81 //void context_EndRequest(object sender, EventArgs e)
82 //{
83 // HttpApplication application = (HttpApplication)sender;
84 // HttpContext context = application.Context;
85 // context.Response.ContentType = "text/html";
86 // context.Response.Charset = "GB2312";
87 // context.Response.ContentEncoding = Encoding.Default;
88 // context.Response.Write("<hr><h1 style='color:#f00'>Treatment from HttpModule,End...</h1>");
89 //}
90
91 }
92 }
复制代码
2. 处理压缩和匹配自定义过滤 CompressWhitespaceFilter.cs
复制代码
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Web;
5 using System.IO;
6 using System.Text;
7 using System.Text.RegularExpressions;
8 using System.IO.Compression;
9
10 namespace Compress.ModuleDemo
11 {
12 public enum CompressOptions
13 {
14 GZip,
15 Deflate,
16 None
17 }
18
19 public class CompressWhitespaceFilter : Stream
20 {
21 StringBuilder responseHtml;
22 const string _cssPattern = "(?<HTML><link[^>]*href\\s*=\\s*[\\\"\\']?(?<HRef>[^\"'>\\s]*)[\\\"\\']?[^>]*>)";
23 const string _jsPattern = "(?<HTML><script[^>]*src\\s*=\\s*[\\\"\\']?(?<SRC>[^\"'>\\s]*)[\\\"\\']?[^>]*></script>)";
24
25 private HttpApplication app;
26 public HttpApplication App
27 {
28 get { return app; }
29 set { app = value; }
30 }
31
32 private GZipStream _contentGZip;
33 private DeflateStream _content_Deflate;
34 private Stream _content;
35 private CompressOptions _options;
36 private bool disposed = false;
37
38 private CompressWhitespaceFilter() { }
39 public CompressWhitespaceFilter(Stream content, CompressOptions options)
40 {
41
42 responseHtml = new StringBuilder();
43 if (options == CompressOptions.GZip)
44 {
45 this._contentGZip = new GZipStream(content, CompressionMode.Compress, true);
46 this._content = this._contentGZip;
47 }
48 else if (options == CompressOptions.Deflate)
49 {
50 this._content_Deflate = new DeflateStream(content, CompressionMode.Compress, true);
51 this._content = this._content_Deflate;
52 }
53 else
54 {
55 this._content = content;
56 }
57 this._options = options;
58 }
59
60 public override bool CanRead
61 {
62 get { return this._content.CanRead; }
63 }
64
65 public override bool CanSeek
66 {
67 get { return this._content.CanSeek; }
68 }
69
70 public override bool CanWrite
71 {
72 get { return this._content.CanWrite; }
73 }
74
75 /// <summary>
76 /// When overriding in a derived class, all buffers of the stream are cleared and all buffer data is written to the underlying device
77 /// </summary>
78 public override void Flush()
79 {
80 this._content.Flush();
81 //Test
82 //this._content.Dispose();
83 //this._contentGZip.Dispose();
84 }
85
86
87 /// <summary>
88 /// 重写Dispose方法,释放派生类自己的资源,并且调用基类的Dispose方法
89 /// 使Gzip把缓存中余下的内容全部写入MemoryStream中,因为只有在Gzip流释放之后才能去承载对象中读取数据或判断数据大小
90 /// </summary>
91 /// <param name="disposing"></param>
92 protected override void Dispose(bool disposing)
93 {
94 if (!this.disposed)
95 {
96 try
97 {
98 if (disposing)
99 {
100 // Release the managed resources you added in this derived class here.
101 //xx.Dispose();
102 }
103
104 // Release the native unmanaged resources you added in this derived class here.
105 // xx.Close()
106
107 //if (_contentGZip != null)
108 // _contentGZip.Close();
109
110 //if (_content_Deflate != null)
111 // _content_Deflate.Close();
112
113 this._content.Close();
114 this.disposed = true;
115 }
116 finally
117 {
118 // Call Dispose on your base class.
119 base.Dispose(disposing);
120 }
121 }
122 }
123
124 public override long Length
125 {
126 get { return this._content.Length; }
127 }
128
129 public override long Position
130 {
131 get
132 {
133 return this._content.Position;
134 }
135 set
136 {
137 this._content.Position = value;
138 }
139 }
140
141 public override int Read(byte[] buffer, int offset, int count)
142 {
143 return this._content.Read(buffer, offset, count);
144 }
145
146 public override long Seek(long offset, SeekOrigin origin)
147 {
148 return this._content.Seek(offset, origin);
149 }
150
151 public override void SetLength(long value)
152 {
153 this._content.SetLength(value);
154 }
155
156 public override void Write(byte[] buffer, int offset, int count)
157 {
158 byte[] data = new byte[count + 1];
159 Buffer.BlockCopy(buffer, offset, data, 0, count);
160 string s = System.Text.Encoding.UTF8.GetString(data);
161 s = Regex.Replace(s, "^\\s*", string.Empty, RegexOptions.Compiled | RegexOptions.Multiline);
162 s = Regex.Replace(s, "\\r\\n", string.Empty, RegexOptions.Compiled | RegexOptions.Multiline);
163 s = Regex.Replace(s, "<!--*.*?-->", string.Empty, RegexOptions.Compiled | RegexOptions.Multiline);
164 byte[] outdata = System.Text.Encoding.UTF8.GetBytes(s);
165 this._content.Write(outdata, 0, outdata.GetLength(0));
166 }
167
168
169 /// <summary>
170 /// Replcase stylesheet links with ones pointing to HttpHandlers that compress and cache the css
171 /// </summary>
172 /// <param name="html"></param>
173 /// <returns></returns>
174 public string ReplaceCss(string html)
175 {
176 // create a list of the stylesheets
177 List<string> stylesheets = new List<string>();
178 // create a dictionary used for combining css in the same directory
179 Dictionary<string, List<string>> css = new Dictionary<string, List<string>>();
180
181 // create a base uri which will be used to get the uris to the css
182 Uri baseUri = new Uri(app.Request.Url.AbsoluteUri);
183
184 // loop through each match
185 foreach (Match match in Regex.Matches(html, _cssPattern, RegexOptions.IgnoreCase))
186 {
187 // this is the enire match and will be used to replace the link
188 string linkHtml = match.Groups[0].Value;
189 // this is the href of the link
190 string href = match.Groups[2].Value;
191
192 // get a uri from the base uri, this will resolve any relative and absolute links
193 Uri uri = new Uri(baseUri, href);
194 string file = "";
195 // check to see if it is a link to a local file
196 if (uri.Host == baseUri.Host)
197 {
198 // check to see if it is local to the application
199 if (uri.AbsolutePath.ToLower().StartsWith(app.Context.Request.ApplicationPath.ToLower()))
200 {
201 // this combines css files in the same directory into one file (actual combining done in HttpHandler)
202 int index = uri.AbsolutePath.LastIndexOf("/");
203 string path = uri.AbsolutePath.Substring(0, index + 1);
204 file = uri.AbsolutePath.Substring(index + 1);
205 if (!css.ContainsKey(path))
206 css.Add(path, new List<string>());
207 css[path].Add(file + (href.Contains("?") ? href.Substring(href.IndexOf("?")) : ""));
208 // replace the origianl links with blanks
209 html = html.Replace(linkHtml, "");
210 // continue to next link
211 continue;
212 }
213 else
214 file = uri.AbsolutePath + uri.Query;
215 }
216 else
217 file = uri.AbsoluteUri;
218 string newLinkHtml = linkHtml.Replace(href, "css.axd?files=" + file);
219
220 // just replace the link with the new link
221 html = html.Replace(linkHtml, newLinkHtml);
222 }
223
224 StringBuilder link = new StringBuilder();
225 link.AppendLine("");
226 foreach (string key in css.Keys)
227 {
228 link.AppendLine(string.Format("<link href='{0}css.axd?files={1}' type='text/css' rel='stylesheet' />", key, string.Join(",", css[key].ToArray())));
229
230 }
231
232 // find the head tag and insert css in the head tag
233 int x = html.IndexOf("<head");
234 int num = 0;
235 if (x > -1)
236 {
237 num = html.Substring(x).IndexOf(">");
238 html = html.Insert(x + num + 1, link.ToString());
239 }
240 return html;
241 }
242
243 /// <summary>
244 /// Replcase javascript links with ones pointing to HttpHandlers that compress and cache the javascript
245 /// </summary>
246 /// <param name="html"></param>
247 /// <returns></returns>
248 public string ReplaceJS(string html)
249 {
250 // if the javascript is in the head section of the html, then try to combine the javascript into one
251 int start, end;
252 if (html.Contains("<head") && html.Contains("</head>"))
253 {
254 start = html.IndexOf("<head");
255 end = html.IndexOf("</head>");
256 string head = html.Substring(start, end - start);
257
258 head = ReplaceJSInHead(head);
259
260 html = html.Substring(0, start) + head + html.Substring(end);
261 }
262
263 // javascript that is referenced in the body is usually used to write content to the page via javascript,
264 // we don't want to combine these and place them in the header since it would cause problems
265 // or it is a WebResource.axd or ScriptResource.axd
266 if (html.Contains("<body") && html.Contains("</body>"))
267 {
268 start = html.IndexOf("<body");
269 end = html.IndexOf("</body>");
270 string head = html.Substring(start, end - start);
271
272 head = ReplaceJSInBody(head);
273
274 html = html.Substring(0, start) + head + html.Substring(end);
275 }
276
277 return html;
278 }
279
280 /// <summary>
281 /// Replaces the js in the head tag. (see ReplaceCss for comments)
282 /// </summary>
283 /// <param name="html"></param>
284 /// <returns></returns>
285 public string ReplaceJSInHead(string html)
286 {
287 List<string> javascript = new List<string>();
288 Dictionary<string, List<string>> js = new Dictionary<string, List<string>>();
289
290 Uri baseUri = new Uri(app.Request.Url.AbsoluteUri);
291 foreach (Match match in Regex.Matches(html, _jsPattern, RegexOptions.IgnoreCase))
292 {
293 string linkHtml = match.Groups[0].Value;
294 string src = match.Groups[2].Value;
295
296 Uri uri = new Uri(baseUri, src);
297 if (!Path.GetExtension(uri.AbsolutePath).Equals("js") && uri.AbsolutePath.Contains("WebResource.axd"))
298 continue;
299 if (uri.Host == baseUri.Host)
300 {
301 if (uri.AbsolutePath.ToLower().StartsWith(app.Context.Request.ApplicationPath.ToLower()))
302 {
303 int index = uri.AbsolutePath.LastIndexOf("/");
304 string path = uri.AbsolutePath.Substring(0, index + 1);
305 string file = uri.AbsolutePath.Substring(index + 1);
306 if (!js.ContainsKey(path))
307 js.Add(path, new List<string>());
308 js[path].Add(file + (src.Contains("?") ? src.Substring(src.IndexOf("?")) : ""));
309 }
310 else
311 javascript.Add(uri.AbsolutePath + uri.Query);
312
313 }
314 else
315 javascript.Add(uri.AbsoluteUri);
316 html = html.Replace(linkHtml, "");
317 }
318
319 int x = html.IndexOf("<head");
320 int num = html.Substring(x).IndexOf(">");
321 string link = "";
322
323 foreach (string key in js.Keys)
324 {
325 link = string.Format("<script src='{0}js.axd?files={1}' type='text/javascript' ></script>", key, string.Join(",", js[key].ToArray()));
326 html = html.Insert(x + num + 1, link + Environment.NewLine);
327
328 }
329 if (javascript.Count > 0)
330 {
331 link = string.Format("<script src='js.axd?files={0}' type='text/javascript' /></script>", string.Join(",", javascript.ToArray()));
332 html = html.Insert(x + num + 1, link + Environment.NewLine);
333 }
334 return html;
335 }
336
337 /// <summary>
338 /// Replaces the js in the body. (see ReplaceCss for comments)
339 /// </summary>
340 /// <param name="html"></param>
341 /// <returns></returns>
342 public string ReplaceJSInBody(string html)
343 {
344 Uri baseUri = new Uri(app.Request.Url.AbsoluteUri);
345 foreach (Match match in Regex.Matches(html, _jsPattern, RegexOptions.IgnoreCase))
346 {
347 string linkHtml = match.Groups[0].Value;
348 string src = match.Groups[2].Value;
349
350
351 Uri uri = new Uri(baseUri, src);
352 if (!uri.AbsolutePath.EndsWith(".js") && !uri.AbsolutePath.Contains("WebResource.axd"))
353 continue;
354 string file = "";
355 string path = "";
356 if (uri.Host == baseUri.Host)
357 {
358 if (uri.AbsolutePath.ToLower().StartsWith(app.Context.Request.ApplicationPath.ToLower()))
359 {
360 int index = uri.AbsolutePath.LastIndexOf("/");
361 path = uri.AbsolutePath.Substring(0, index + 1);
362 file = uri.AbsolutePath.Substring(index + 1) + (src.Contains("?") ? src.Substring(src.IndexOf("?")) : "");
363 }
364 else
365 file = uri.AbsolutePath + uri.Query;
366 }
367 else
368 file = uri.AbsoluteUri;
369 string newLinkHtml = linkHtml.Replace(src, path + "js.axd?files=" + file);
370 html = html.Replace(linkHtml, newLinkHtml);
371 }
372 return html;
373 }
374
375 }
376 }
复制代码
在这里需要注意的是对GZIP 的释放,否则流数据会读取不到:
复制代码
1 /// <summary>
2 /// 重写Dispose方法,释放派生类自己的资源,并且调用基类的Dispose方法
3 /// 使Gzip把缓存中余下的内容全部写入MemoryStream中,因为只有在Gzip流释放之后才能去承载对象中读取数据或判断数据大小
4 /// </summary>
5 /// <param name="disposing"></param>
6 protected override void Dispose(bool disposing)
7 {
8 if (!this.disposed)
9 {
10 try
11 {
12 if (disposing)
13 {
14 // Release the managed resources you added in this derived class here.
15 //xx.Dispose();
16 }
17
18 // Release the native unmanaged resources you added in this derived class here.
19 // xx.Close()
20
21 //if (_contentGZip != null)
22 // _contentGZip.Close();
23
24 //if (_content_Deflate != null)
25 // _content_Deflate.Close();
26
27 this._content.Close();
28 this.disposed = true;
29 }
30 finally
31 {
32 // Call Dispose on your base class.
33 base.Dispose(disposing);
34 }
35 }
36 }
复制代码
对于C#非托管资源释放(Finalize/Dispose)方法理解:
http://www.cnblogs.com/lzhdim/archive/2009/11/04/1595845.html
© Copyright 2014 - 2024 柏港建站平台 ejk5.com. 渝ICP备16000791号-4