狼Robot

三人行,必有我师。

利用HttpModule和ResponseFilter来压缩你的html

  不知道大家有没有注意过google和baidu首页页面的html,打开一看你会发现,竟然没有缩排什么,几乎整个页面输出都快写成一行了,至于为什么这样做,我能想到的是节省流量,没别的想法了.那我们是不是也可以做到这样呢(虽然我们对流量没什么要求),当然是可以的,写代码的时候不要缩排,把html全部写在一行不就行了,当然这个方法的确可行,但是麻烦了点,而且维护起来也不方便.有没有更好的办法,当然是有,我们就利用HttpModule和Response.Filter来实现这个功能吧,废话说完了,切入正题.

 

  既然是用HttpModule,那当然就得弄个实现了IHttpModule的类了:

 1using System;
 2using System.Collections.Generic;
 3using System.Text;
 4using System.Web;
 5
 6namespace K2046.Handlers
 7{
 8    public class FilterModule : IHttpModule
 9    {
10        IHttpModule 成员
31    }

32}

 

  在Web.Config的<system.web>中再加上如下代码:

1<httpModules>
2            <add name="ResponseFilter" type="K2046.Handlers.FilterModule, K2046.Handlers"/>
3        </httpModules>

 

  在这里面用到了一个ResponseFilter的类,这个也是自己实现的,代码如下:

 1using System;
 2using System.Collections.Generic;
 3using System.Text;
 4using System.IO;
 5using System.Text.RegularExpressions;
 6
 7namespace K2046.Handlers
 8{
 9    public class ResponseFilter : Stream
10    {
11        private Stream _StreamFilter;
12
13        private ResponseFilter() { }
14
15        public ResponseFilter(Stream stream)
16        {
17            _StreamFilter = stream;
18        }

19
20        public override bool CanRead
21        {
22            get return true; }
23        }

24
25        public override bool CanSeek
26        {
27            get return true; }
28        }

29
30        public override bool CanWrite
31        {
32            get return true; }
33        }

34
35        public override void Flush()
36        {
37            _StreamFilter.Flush();
38        }

39
40        public override long Length
41        {
42            get
43            {
44                return _StreamFilter.Length;
45            }

46        }

47
48        public override long Position
49        {
50            get
51            {
52                return _StreamFilter.Position;
53            }

54            set
55            {
56                _StreamFilter.Position = value;
57            }

58        }

59
60        public override int Read(byte[] buffer, int offset, int count)
61        {
62            return _StreamFilter.Read(buffer, offset, count);
63        }

64
65        public override long Seek(long offset, SeekOrigin origin)
66        {
67            return _StreamFilter.Seek(offset, origin);
68        }

69
70        public override void SetLength(long value)
71        {
72            _StreamFilter.SetLength(value);
73        }

74
75        public override void Write(byte[] buffer, int offset, int count)
76        {
77            string Html = Encoding.UTF8.GetString(buffer);
78            Html = Regex.Replace(Html, @">\s+?<""><");//去除Html中的空白字符.
79            Html = Regex.Replace(Html, @"\r\n\s*""");
80            Html = Regex.Replace(Html, @"<body([\s|\S]*?)>([\s|\S]*?)</body>"@"<body$1>$2<!--Hello,Robot!--></body>", RegexOptions.IgnoreCase);
81            buffer = Encoding.UTF8.GetBytes(Html);
82            _StreamFilter.Write(buffer, offset, buffer.Length);
83        }

84    }

85}

86

 

  其实这个类没做什么,继承Stream,重写Write方法,就可以了,不过关键的就是这里了,在Write的时候,先把byte[]转成string,再把这个string按你想要的方式处理,你想把它整成什么样就整成什么样了.处理完了,再把string转成byte[],然后写入原来的stream里,就OK了.

 

  我现在只是把一些空白字符去掉了,还可以干什么就看自己需要了.

 

  注意:在FilterModule里,所有的请求都会被ResponseFilter处理,包括axd文件什么的,所以会造成输出有问题,所以在加ResponseFilter的时候自己要处理一下条件.

 

  第一次发.NET的文章,写得不好请大家见谅,欢迎各位砖家指点.谢谢.

 

  更新:其实记录这篇文章的原意是实现如何改写输出的流,没找到合适的东西,就用在压缩html上了,当然,也只是简单的去除了空白字符而已,重要的是实现在HttpModule里改写了输出的流.因为之前有碰到过这样的问题,找相关Response.Filter的资料也不多,有些也说得不是那么清楚,所以,做个笔记.

 

Demo项目下载.

posted on 2008-07-22 14:07 狼Robot 阅读(2001) 评论(28)  编辑 收藏 所属分类: C#

评论

#1楼  2008-07-22 14:08 真见      

学习。。。   回复  引用  查看    

#2楼  2008-07-22 14:13 hxm      

和用7 ZIP和GZIP压缩的方案比较起来呢   回复  引用  查看    

#3楼 [楼主] 2008-07-22 14:16 狼Robot      

@真见
同学

@hxm
不好意思,我没看过7 ZIP和GZIP,能否给些相应的链接,谢谢.   回复  引用  查看    

#4楼  2008-07-22 14:29 王孟军!      

@hxm
这位兄弟是说压缩状态数据吧?

@狼Robot
这种方式,如果不影响性能,倒是不错!

还有就是
<add name="ResponseFilter" type="K2046.Handlers.FilterModule, K2046.Handlers"/>
name的值,可以随便配置,不一定要是”ResponseFilter“
个人见解,见笑   回复  引用  查看    

#5楼  2008-07-22 14:33 Allie      

我觉得没有必要 开启gzip就差不多可以了~现在的带宽不需要你这么节省。。   回复  引用  查看    

#6楼  2008-07-22 14:37 baal [未注册用户]

我还真是晕了,进来一看才发现,去掉空格就叫压缩。晕菜   回复  引用    

#7楼 [楼主] 2008-07-22 14:43 狼Robot      

@王孟军!
明白,谢谢.

@Allie
只是提出一种实现方式,不是鼓励大家这样做,压缩只是出来的一个结果,其实原本我想要说的是在HttpModule中改写输出.

@baal
不好意思,把您给骗进来了.   回复  引用  查看    

#8楼  2008-07-22 15:35 benbenx      

杀死Baal,可以掉好装备。   回复  引用  查看    

#9楼  2008-07-22 16:15 飞笑      

我想将防注入做到这httpmodule里,以前的做法是看到sql非法字符直接卡掉,但很不合适,不如替换。此方法貌似可以,但还是有些问题。   回复  引用  查看    

#10楼  2008-07-22 16:50 火无极      

楼主最近出文章比较勤快啊!   回复  引用  查看    

#11楼  2008-07-22 16:54 吃请客 [未注册用户]

--引用--------------------------------------------------
火无极: 楼主最近出文章比较勤快啊!
--------------------------------------------------------
  回复  引用    

#12楼 [楼主] 2008-07-22 16:55 狼Robot      

@benbenx
.............

@飞笑
防注入?难道你要用在Request.Filter上么?我以前也这么想过,不过如果碰到上传文件的表单,该怎么处理呢?

@火无极
没事做做笔记,呵呵,谢谢捧场.   回复  引用  查看    

#13楼  2008-07-22 17:10 武眉博<活靶子.Net>      

我就这么弄的
see: http://www.devedu.com   回复  引用  查看    

#14楼  2008-07-22 17:51 birdshome      

费cpu啊。。。
字符串扫描,正则引擎,编码转换,都不是省油的灯   回复  引用  查看    

#15楼  2008-07-22 17:52 傲然林      

貌似以前偶也在网上找资料捣鼓了一个,但是还是有一个问题。   回复  引用  查看    

#16楼 [楼主] 2008-07-22 17:59 狼Robot      

@武眉博&lt;活靶子.Net&gt;
嗯.看了,不知道实际用的时候有没有碰到过什么问题?

@birdshome
我暂时还没考虑到性能的问题......

@傲然林
有什么问题呢?能透露一下机密么?   回复  引用  查看    

#17楼  2008-07-22 18:32 Ryan Gene      

此法玩玩可以,用在实战中就。。。   回复  引用  查看    

#18楼  2008-07-22 18:36 代码乱了      

的这个方案,以前见过,具体没有测试过,单纯的压缩ViewState的话,性能上不会有多大损失的
我以前用过Response.Filter获取Response.Write()的内容,感觉蛮方便的
http://topic.csdn.net/u/20070906/23/e670dbc5-9814-427f-862f-181ba9a86547.html   回复  引用  查看    

#19楼  2008-07-22 22:02 傲然林      

偶给搞忘记了,反正有点点问题。好像是对于JS注释没有加以处理。   回复  引用  查看    

#20楼  2008-07-23 00:03 Jeffrey Zhao      

这种Regex替换方法消耗太多CPU,我估计性能降低实在太多   回复  引用  查看    

#21楼 [楼主] 2008-07-23 00:10 狼Robot      

@傲然林
是的.js注释是会出现问题.

@Jeffrey Zhao
老赵总是在凌晨出现,不知道有没有好的办法解决CPU消耗的问题呢?
  回复  引用  查看    

#22楼  2008-07-23 09:04 沈阳阿瑞      

是啊,省了一点点带宽,浪费了很多CPU,
不值得。   回复  引用  查看    

#23楼  2008-07-23 09:49 Jeffrey Zhao      

@狼Robot
作Regex匹配是必然会出现这个问题的……要解决的话,对于ASP.NET来说就在源代码级别删除空格。   回复  引用  查看    

#24楼  2008-07-23 10:16 Vincent Zhou      

我来学习。。。   回复  引用  查看    

#25楼 [楼主] 2008-07-23 10:19 狼Robot      

@Jeffrey Zhao
源代码中删除空格好像比较麻烦,这样,维护代码的时候很累吧.

@Vincent Zhou
同学

@沈阳阿瑞
大家都说性能的问题,看来我得考虑下性能才行.   回复  引用  查看    

#26楼  2008-07-30 17:14 Kevan      

问题来了!!
如果是正常的文章段落
<pre>
asdas(回车符)
sadasd(回车符)
<pre>

全被替换没了哦。呵呵

直接用 Regex.Replace(Html, @"\s+(?=<)|\s+$|(?<=>)\s+", "") 吧   回复  引用  查看    

#27楼  2008-07-30 17:48 Kevan      

@Kevan
哈哈,楼主的代码真晕,竟然直接处理掉了 \r\n 服了!

如果页面有CSS代码,JS代码,那不就是完蛋了?

还是用我的正则吧。。。我测试过,完美压缩。。。
  回复  引用  查看    

#28楼 [楼主] 2008-07-30 20:29