ASP.NET页面载入速度提高的一些做法:   1.采用 HTTP Module 控制页面的生命周期。   2.自定义Response.Filter得到输出流stream生成动态页面的静态内容(磁盘缓存)。   3.页面GZIP压缩。   4.OutputCache 编程方式输出页面缓存。   5.删除页面空白字符串。(类似Google)   6.完全删除ViewState。   7.删除服务器控件生成的垃圾NamingContainer。   8.使用计划任务按时生成页面。(本文不包含该做法的实现)   9.JS,CSS压缩、合并、缓存,图片缓存。(限于文章篇幅,本文不包含该做法的实现)   10.缓存破坏。(不包含第9做法的实现)    针对上述做法,我们首先需要一个HTTP模块,它是整个页面流程的入口和核心。   一、自定义Response.Filter得到输出流stream生成动态页面的静态内容(磁盘缓存)   如下的代码我们可以看出,我们以 request.RawUrl 为缓存基础,因为它可以包含任意的QueryString变量,然后我们用MD5加密RawUrl 得到服务器本地文件名的变量,再实例化一个FileInfo操作该文件,如果文件最后一次生成时间小于7天,我们就使用.Net2.0新增的TransmitFile方法将存储文件的静态内容发送到浏览器。如果文件不存在,我们就操作 response.Filter 得到的 Stream 传递给 CommonFilter 类,并利用FileStream写入动态页面的内容到静态文件中。

namespace ASPNETCode.HttpModules
{
public class CommonModule : IHttpModule
{
public void Init(HttpApplication application)
{
application.BeginRequest += Application_BeginRequest;
}
private void Application_BeginRequest(object sender, EventArgs e)
{
var context = HttpContext.Current;
var request = context.Request;
var url = request.RawUrl;
var response = context.Response;
var path = GetPath(url);
var file = new FileInfo(path);
if (DateTime.Now.Subtract(file.LastWriteTime).TotalDays < )
{
response.TransmitFile(path);
response.End();
return;
}
try
{
var stream = file.OpenWrite();
response.Filter = new CommonFilter(response.Filter, stream);
}
catch (Exception)
{
//Log.Insert("");
}
}
public void Dispose()
{
}
private static string GetPath(string url)
{
var hash = Hash(url);
string fold = HttpContext.Current.Server.MapPath("~/Temp/");
return string.Concat(fold, hash);
}
private static string Hash(string url)
{
url = url.ToUpperInvariant();
var md5 = new System.Security.Cryptography.MD5CryptoServiceProvider();
var bs = md5.ComputeHash(Encoding.ASCII.GetBytes(url));
var s = new StringBuilder();
foreach (var b in bs)
{
s.Append(b.ToString("x2").ToLower());
}
return s.ToString();
}
}
}

二、页面GZIP压缩     对页面GZIP压缩几乎是每篇讲解高性能WEB程序的几大做法之一,因为使用GZIP压缩可以降低服务器发送的字节数,能让客户感觉到网页的速度更快也减少了对带宽的使用情况。当然,这里也存在客户端的浏览器是否支持它。因此,我们要做的是,如果客户端支持GZIP,我们就发送GZIP压缩过的内容,如果不支持,我们直接发送静态文件的内容。幸运的是,现代浏览器IE6.7.8.0,火狐等都支持GZIP。 为了实现这个功能,我们需要改写上面的 Application_BeginRequest 事件:

private void Application_BeginRequest(object sender, EventArgs e)
{
var context = HttpContext.Current;
var request = context.Request;
var url = request.RawUrl;
var response = context.Response;
var path = GetPath(url);
var file = new FileInfo(path);
// 使用页面压缩
ResponseCompressionType compressionType = this.GetCompressionMode(request);
if (compressionType != ResponseCompressionType.None)
{
response.AppendHeader("Content-Encoding", compressionType.ToString().ToLower());
if (compressionType == ResponseCompressionType.GZip)
{
response.Filter = new GZipStream(response.Filter, CompressionMode.Compress);
}
else
{
response.Filter = new DeflateStream(response.Filter, CompressionMode.Compress);
}
}
if (DateTime.Now.Subtract(file.LastWriteTime).TotalMinutes < )
{
response.TransmitFile(path);
response.End();
return;
}
try
{
var stream = file.OpenWrite();
response.Filter = new CommonFilter(response.Filter, stream);
}
catch (Exception)
{
//Log.Insert("");
}
}
private ResponseCompressionType GetCompressionMode(HttpRequest request)
{
string acceptEncoding = request.Headers["Accept-Encoding"];
if (string.IsNullOrEmpty(acceptEncoding))
return ResponseCompressionType.None;
acceptEncoding = acceptEncoding.ToUpperInvariant();
if (acceptEncoding.Contains("GZIP"))
return ResponseCompressionType.GZip;
else if (acceptEncoding.Contains("DEFLATE"))
return ResponseCompressionType.Deflate;
else
return ResponseCompressionType.None;
}
private enum ResponseCompressionType
{
None,
GZip,
Deflate
}

三、OutputCache 编程方式输出页面缓存   ASP.NET内置的 OutputCache 缓存可以将内容缓存在三个地方:Web服务器、代理服务器和浏览器。当用户访问一个被设置为 OutputCache的页面时,ASP.NET在MSIL之后,先将结果写入output cache缓存,然后在发送到浏览器,当用户访问同一路径的页面时,ASP.NET将直接发送被Cache的内容,而不经过.aspx编译以及执行MSIL的过程,所以,虽然程序的本身效率没有提升,但是页面载入速度却得到了提升。 为了实现这个功能,我们继续改写上面的 Application_BeginRequest 事件,我们在 TransmitFile 后,将这个路径的页面以OutputCache编程的方式缓存起来:

private void Application_BeginRequest(object sender, EventArgs e)
{
if (DateTime.Now.Subtract(file.LastWriteTime).TotalMinutes < )
{
response.TransmitFile(path);
// 添加 OutputCache 缓存头,并缓存在客户端
response.Cache.SetExpires(DateTime.Now.AddMinutes());
response.Cache.SetCacheability(HttpCacheability.Public);
response.End();
return;
}
}

四、实现CommonFilter类过滤ViewState、过滤NamingContainer、空白字符串,以及生成磁盘的缓存文件   我们传入response.Filter的Stream对象给CommonFilter类:   首先,我们用先Stream的Write方法实现生成磁盘的缓存文件,代码如下,在这些代码中,只有初始化构造函数,Write方法,Close方式是有用的,其中FileStream字段是生成静态文件的操作对象:

namespace ASPNETCode.HttpModules
{
public class CommonFilter : Stream
{
private readonly Stream _responseStream;
private readonly FileStream _cacheStream; public override bool CanRead
{
get
{
return false;
}
}
public override bool CanSeek
{
get
{
return false;
}
}
public override bool CanWrite
{
get
{
return _responseStream.CanWrite;
}
}
public override long Length
{
get
{
throw new NotSupportedException();
}
}
public override long Position
{
get
{
throw new NotSupportedException();
}
set
{
throw new NotSupportedException();
}
} public CommonFilter(Stream responseStream, FileStream stream)
{
_responseStream = responseStream;
_cacheStream = stream;
} public override long Seek(long offset, SeekOrigin origin)
{
throw new NotSupportedException();
}
public override void SetLength(long length)
{
throw new NotSupportedException();
}
public override int Read(byte[] buffer, int offset, int count)
{
throw new NotSupportedException();
}
public override void Flush()
{
_responseStream.Flush();
_cacheStream.Flush();
}
public override void Write(byte[] buffer, int offset, int count)
{
_cacheStream.Write(buffer, offset, count);
_responseStream.Write(buffer, offset, count);
}
public override void Close()
{
_responseStream.Close();
_cacheStream.Close();
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
_responseStream.Dispose();
_cacheStream.Dispose();
}
}
}
}

然后我们利用正则完全删除ViewState:

// 过滤ViewState
private string ViewStateFilter(string strHTML)
{
string matchString1 = "type=\"hidden\" name=\"__VIEWSTATE\" id=\"__VIEWSTATE\"";
string matchString2 = "type=\"hidden\" name=\"__EVENTVALIDATION\" id=\"__EVENTVALIDATION\"";
string matchString3 = "type=\"hidden\" name=\"__EVENTTARGET\" id=\"__EVENTTARGET\"";
string matchString4 = "type=\"hidden\" name=\"__EVENTARGUMENT\" id=\"__EVENTARGUMENT\""; string positiveLookahead1 = "(?=.*(" + Regex.Escape(matchString1) + "))";
string positiveLookahead2 = "(?=.*(" + Regex.Escape(matchString2) + "))";
string positiveLookahead3 = "(?=.*(" + Regex.Escape(matchString3) + "))";
string positiveLookahead4 = "(?=.*(" + Regex.Escape(matchString4) + "))"; RegexOptions opt = RegexOptions.IgnoreCase | RegexOptions.Singleline | RegexOptions.CultureInvariant | RegexOptions.Compiled; Regex[] arrRe = new Regex[] {
new Regex("\\s*<div>" + positiveLookahead1 + "(.*?)</div>\\s*", opt),
new Regex("\\s*<div>" + positiveLookahead2 + "(.*?)</div>\\s*", opt),
new Regex("\\s*<div>" + positiveLookahead3 + "(.*?)</div>\\s*", opt),
new Regex("\\s*<div>" + positiveLookahead3 + "(.*?)</div>\\s*", opt),
new Regex("\\s*<div>" + positiveLookahead4 + "(.*?)</div>\\s*", opt)
}; foreach (Regex re in arrRe)
{
strHTML = re.Replace(strHTML, "");
}
return strHTML;
}

以下是删除页面空白的方法:

// 删除空白
private Regex tabsRe = new Regex("\\t", RegexOptions.Compiled | RegexOptions.Multiline);
private Regex carriageReturnRe = new Regex(">\\r\\n<", RegexOptions.Compiled | RegexOptions.Multiline);
private Regex carriageReturnSafeRe = new Regex("\\r\\n", RegexOptions.Compiled | RegexOptions.Multiline);
private Regex multipleSpaces = new Regex(" ", RegexOptions.Compiled | RegexOptions.Multiline);
private Regex spaceBetweenTags = new Regex(">\\s<", RegexOptions.Compiled | RegexOptions.Multiline);
private string WhitespaceFilter(string html)
{
html = tabsRe.Replace(html, string.Empty);
html = carriageReturnRe.Replace(html, "><");
html = carriageReturnSafeRe.Replace(html, " ");
while (multipleSpaces.IsMatch(html))
html = multipleSpaces.Replace(html, " ");
html = spaceBetweenTags.Replace(html, "><");
html = html.Replace("//<![CDATA[", "");
html = html.Replace("//]]>", "");
return html;
}

以下是删除ASP.NET控件的垃圾UniqueID名称方法:

// 过滤NamingContainer
private string NamingContainerFilter(string html)
{
RegexOptions opt =
RegexOptions.IgnoreCase |
RegexOptions.Singleline |
RegexOptions.CultureInvariant |
RegexOptions.Compiled;
Regex re = new Regex("( name=\")(?=.*(" + Regex.Escape("$") + "))([^\"]+?)(\")", opt);
html = re.Replace(html, new MatchEvaluator(delegate(Match m)
{
int lastDollarSignIndex = m.Value.LastIndexOf('$');
if (lastDollarSignIndex >= )
{
return m.Groups[].Value + m.Value.Substring(lastDollarSignIndex + );
}
else
{
return m.Value;
}
}));
return html;
}

最后,我们把以上过滤方法整合到CommonFilter类的Write方法:

public override void Write(byte[] buffer, int offset, int count)
{
// 转换buffer为字符串
byte[] data = new byte[count];
Buffer.BlockCopy(buffer, offset, data, , count);
string html = System.Text.Encoding.UTF8.GetString(buffer); // 以下整合过滤方法
html = NamingContainerFilter(html);
html = ViewStateFilter(html);
html = WhitespaceFilter(html);
byte[] outdata = System.Text.Encoding.UTF8.GetBytes(html); // 写入磁盘
_cacheStream.Write(outdata, , outdata.GetLength());
_responseStream.Write(outdata, , outdata.GetLength());
}

五、缓存破坏   经过以上程序的实现,网页已经被高速缓存在客户端了,如果果用户访问网站被缓存过的页面,则页面会以0请求的速度加载页面。但是,如果后台更新了某些数据,前台用户则不能及时看到最新的数据,因此要改变这种情况,我们必须破坏缓存。根据我们如上的程序,我们破坏缓存只需要做2步:更新服务器上的临时文件,删除OutputCache过的页面。   更新服务器上的文件我们只需删除这个文件即可,当某一用户第一次访问该页面时会自动生成,当然,你也可以用程序先删除后生成:

// 更新文件
foreach ( var file in Directory.GetFiles( HttpRuntime.AppDomainAppPath + "Temp" ) ) {
File.Delete( file );
}

要删除OutputCache关联的缓存项,代码如下,我们只需要保证该方法的参数,指页面的绝对路径是正确的,路径不能使用../这样的相对路径:

// 删除缓存
HttpResponse.RemoveOutputCacheItem( "/Default.aspx" );

优化并未结束,战斗还在继续……

感谢  五度苍穹  分享

ASP.NET页面优化,提高载入速度[转]的更多相关文章

  1. ASP.NET页面优化性能提升方法记录

    今天与大家分享:一种优化页面执行速度的方法.采用这个方法,可以使用页面的执行速度获得[8倍]的提升效果. 为了让您对优化的效果有个直观的了解,我准备了下面的测试结果截图: 测试环境:1. Window ...

  2. 记一次完整的asp.net-mvc页面优化过程

    最近在重构一个以前团队开发留下的MVC项目,项目结构堪称混乱,问题多多,但今天说的是页面打开速度的问题.项目中包括web后台系统,几乎随便点一个页面都要盯着白屏等待2-5秒之久,体验很差.通过对页面性 ...

  3. BLOB或TEXT字段使用散列值和前缀索引优化提高查询速度

    1.创建表,存储引擎为myisam,对大文本字段blob使用MD5函数建立一个散列值 create table t2(id varchar(60), content blob, hash_value ...

  4. 如何提高ASP.NET页面载入速度的方法

    前言 本文是我对ASP.NET页面载入速度提高的一些做法,这些做法分为以下部分: 1.采用 HTTP Module 控制页面的生命周期. 2.自定义Response.Filter得到输出流stream ...

  5. 提高ASP.NET页面载入速度的方法

    前言 本文是我对ASP.NET页面载入速度提高的一些做法,这些做法分为以下部分: 目录 1.采用 HTTP Module 控制页面的生命周期. 2.自定义Response.Filter得到输出流str ...

  6. Web前端性能优化——提高页面加载速度

    前言:  在同样的网络环境下,两个同样能满足你的需求的网站,一个“Duang”的一下就加载出来了,一个纠结了半天才出来,你会选择哪个?研究表明:用户最满意的打开网页时间是2-5秒,如果等待超过10秒, ...

  7. jsp的凝视可能会影响页面载入速度

    在jsp页面使用"<!-- -->"的凝视,凝视里面的java代码还是会得到运行,能够再查看页面源码上看到运行完毕的内容,这样就会让不希望运行的代码得到运行.影响载入速 ...

  8. Httpd服务入门知识-使用mod_deflate模块压缩页面优化传输速度

    Httpd服务入门知识-使用mod_deflate模块压缩页面优化传输速度 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.mod_deflate模块概述 mod_deflate ...

  9. 页面优化——js异步载入

    同步载入 在介绍js异步载入之前.我们先来看看什么是js同步载入.我们平时最常使用的就是这样的同步载入形式: <script src="http://XXX.com/script.js ...

随机推荐

  1. centos 下建用户 shell编程

    useradd 用户名 passwd 用户名 cat /etc/passwd  查看用户信息 删除用户 userdel -r   加一个 -r 表示把用户及用户的主目录都删除 su  切换用户 sud ...

  2. Linux环境下apache性能测试工具ab使用详解

    网站性能压力测试是服务器网站性能调优过程中必不可缺少的一环.只有让服务器处在高压情况下,才能真正体现出软件.硬件等各种设置不当所暴露出的问题. 性能测试工具目前最常见的有以下几种:ab.http_lo ...

  3. postfix config

    smtp auth success,other not sure service saslauthd start  [root@localhost ~]# cat /etc/sysconfig/sas ...

  4. Leetcode: Split Array Largest Sum

    Given an array which consists of non-negative integers and an integer m, you can split the array int ...

  5. 一个安邦逻辑漏洞爆破密码的py脚本

    漏洞地址: 安邦保险集团存在逻辑漏洞可遍历用户ID暴力破解用户原始密码进而重置用户密码(附脚本) http://www.wooyun.org/bugs/wooyun-2010-0119851 脚本PO ...

  6. CKplayer功能配置

    开源ckplayer 网页播放器, 跨平台(html5, mobile),flv, f4v, mp4, rtmp协议. webm, ogg, m3u8 ! 博客分类: Javascript /Jque ...

  7. PHP 匹配一个汉字

    使用preg_match 必须使用u flag 这个修饰符添加的额外的功能,与Perl的PCRE不兼容. Pattern和字符串均为UTF-8编码. 从PHP 4.1.0 or greater on ...

  8. Events in ASP.NET Master and Content Pages

    Content page PreInit event. Master page controls Init event. Content controls Init event. Master pag ...

  9. ADT中通过Android SDK Manager去安装x86的image时无法下载

    参考:http://www.crifan.com/adt_android_sdk_manager_can_not_download_package_x86_image/

  10. mysql已有数据字符集转换

    下面模拟把latin1字符集的数据转换为utf8字符集 一.创建测试表和测试数据: 1.修改会话级别的连接字符集 mysql > set names latin1; 查看一下: 2.创建测试表: ...