如何利用客户端缓存对网站进行优化?

        

      介绍

        你的网站在并发访问很大并且无法承受压力的情况下,你会选择如何优化? 
        很多人首先会想从服务器缓存方面着手对程序进行优化,许多不同的服务器缓存方式都有他们自己的特点,像我曾经参与的一些项目中,根据缓存的命中率不同使用过 Com+/Enterprise Libiary Caching/Windows服务,静态文件等方式的服务器端缓存和 HTTP Compression技术,但客户端缓存往往却被人们忽略了,即使服务器的缓存让你的页面访问起来非常地快,但她依然需要依赖浏览器下载并输出,而当你加入客户端缓存时,会给你带来非常多的好处.因为她可以对站点中访问最频繁的页进行缓存充分地提高 Web 服务器的吞吐量(通常以每秒的请求数计算)以提升应用程序性能和可伸缩性。 
        一个在线购物调查显示,大多数人愿意去商店排队,但在在线购物时却不愿意等待。Websense调查公司称多达70%的上网者表示不愿意在页面读取上超过10秒钟。超过70%的人会因为中途速度过慢而取消当前的订单。

      基础知识

        1) 什么是”Last-Modified”? 

        在浏览器第一次请求某一个URL时,服务器端的返回状态会是200,内容是你请求的资源,同时有一个Last-Modified的属性标记此文件在服务期端最后被修改的时间,格式类似这样: 

        Last-Modified: Fri, 12 May 2006 18:53:33 GMT 

        客户端第二次请求此URL时,根据 HTTP 协议的规定,浏览器会向服务器传送 If-Modified-Since 报头,询问该时间之后文件是否有被修改过: 

        If-Modified-Since: Fri, 12 May 2006 18:53:33 GMT 

        如果服务器端的资源没有变化,则自动返回 HTTP 304 (Not Changed.)状态码,内容为空,这样就节省了传输数据量。当服务器端代码发生改变或者重启服务器时,则重新发出资源,返回和第一次请求时类似。 从而保证不向客户端重复发出资源,也保证当服务器有变化时,客户端能够得到最新的资源。 

        2) 什么是”Etag”? 

        HTTP 协议规格说明定义ETag为“被请求变量的实体值” (参见 —— 章节 14.19)。 另一种说法是,ETag是一个可以与Web资源关联的记号(token)。典型的Web资源可以一个Web页,但也可能是JSON或XML文档。服务器单独负责判断记号是什么及其含义,并在HTTP响应头中将其传送到客户端,以下是服务器端返回的格式: 

        ETag: "50b1c1d4f775c61:df3" 

        客户端的查询更新格式是这样的: 

        If-None-Match: W/"50b1c1d4f775c61:df3" 

        如果ETag没改变,则返回状态304然后不返回,这也和Last-Modified一样。本人测试Etag主要在断点下载时比较有用。
        

      Last-Modified和Etags如何帮助提高性能?

        聪明的开发者会把Last-Modified 和ETags请求的http报头一起使用,这样可利用客户端(例如浏览器)的缓存。因为服务器首先产生 Last-Modified/Etag标记,服务器可在稍后使用它来判断页面是否已经被修改。本质上,客户端通过将该记号传回服务器要求服务器验证其(客户端)缓存。 
        过程如下:
                1. 客户端请求一个页面(A)。 
                2. 服务器返回页面A,并在给A加上一个Last-Modified/ETag。 
                3. 客户端展现该页面,并将页面连同Last-Modified/ETag一起缓存。 
                4. 客户再次请求页面A,并将上次请求时服务器返回的Last-Modified/ETag一起传递给服务器。 
                5. 服务器检查该Last-Modified或ETag,并判断出该页面自上次客户端请求之后还未被修改,直接返回响应304和一个空的响应体。


      示例代码

        下面的例子描述如何使用服务器端代码去操作客户端缓存: 

        
 1 //默认缓存的秒数
 2 int secondsTime = 100;
 3 
 4 //判断最后修改时间是否在要求的时间内
 5 //如果服务器端的文件没有被修改过,则返回状态是304,内容为空,这样就节省了传输数据量。如果服务器端的文件被修改过,则返回和第一次请求时类似。
 6 if (request.Headers["If-Modified-Since"!= null && TimeSpan.FromTicks(DateTime.Now.Ticks - DateTime.Parse(request.Headers["If-Modified-Since"]).Ticks).Seconds < secondsTime)
 7 {
 8     //测试代码,在这里会发现,当浏览器返回304状态时,下面的日期并不会输出
 9     Response.Write(DateTime.Now);
10 
11     response.StatusCode = 304;
12     response.Headers.Add("Content-Encoding""gzip");
13     response.StatusDescription = "Not Modified";
14 }
15 else
16 {
17     //输出当前时间
18     Response.Write(DateTime.Now);
19 
20     //设置客户端缓存状态
21     SetClientCaching(response, DateTime.Now);
22 }
23 
24 #region SetClientCaching..
25 /// <summary>
26 /// 设置客户端缓存状态
27 /// </summary>
28 /// <param name="response"></param>
29 /// <param name="lastModified"></param>
30 private void SetClientCaching(HttpResponse response, DateTime lastModified)
31 {
32     response.Cache.SetETag(lastModified.Ticks.ToString());
33     response.Cache.SetLastModified(lastModified);
34     //public 以指定响应能由客户端和共享(代理)缓存进行缓存。
35     response.Cache.SetCacheability(HttpCacheability.Public);
36     //是允许文档在被视为陈旧之前存在的最长绝对时间。
37     response.Cache.SetMaxAge(new TimeSpan(7000));
38     //将缓存过期从绝对时间设置为可调时间
39     response.Cache.SetSlidingExpiration(true);
40 }
41 #endregion


        如果你的缓存是基于文件的方式,如XML或http中的.ashx处理,也可以使用下面的基于文件方式的客户端缓存: 

        
 1 #region SetFileCaching..
 2 /// <summary>
 3 /// 基于文件方式设置客户端缓存
 4 /// </summary>
 5 /// <param name="fileName"></param>
 6 private void SetFileCaching(HttpResponse response, string fileName)
 7 {
 8     response.AddFileDependency(fileName);
 9     //基于处理程序文件依赖项的时间戳设置 ETag HTTP 标头。 
10     response.Cache.SetETagFromFileDependencies();
11     //基于处理程序文件依赖项的时间戳设置 Last-Modified HTTP 标头。
12     response.Cache.SetLastModifiedFromFileDependencies();
13     response.Cache.SetCacheability(HttpCacheability.Public);
14     response.Cache.SetMaxAge(new TimeSpan(7000));
15     response.Cache.SetSlidingExpiration(true);
16 }
17 #endregion

        使用后的效果如下图所示:


上图所使用的工具是在IE下运行的HttpWatchPro,在Firefox下可以使用FireBug+YSlow进行测试.
YSlow是建立在FireBug基础上运行的一个小工具,它可以对你的网页进行分析为什么缓存,并给出评分和缓慢的原因.这个工具来自Yahoo的研发团队,所以规则也是Yahoo制定的.

      结论

        我们已经看了如何使用客户端缓存减少带宽和计算的方法,如前所述,如果能正确合理的利用各种不同的缓存,他们会给你带来很多的好处.我希望本文已为你当下或将来基于Web的项目提供了精神食粮,并正确地在底层利用Last-Modified和ETag响应头去优化你的项目。 

        

参考资料:

301永久重定向实现方式及302重定向

理解ASP.NET与客户端缓存之HTTP协议

 

如何利用客户端缓存对网站进行优化?

posted on 2007-09-24 23:41 Lion 阅读(4944) 评论(30) 编辑 收藏

评论

#1楼  回复 引用   



这个文章写的不错,学习学习!


#2楼  回复 引用 查看   

这个是否与在aspx页面中使用OutputCache语句功能是一致的呢?

<%@ OutputCache Duration="3600" VaryByParam="NONE" %>
2007-09-25 07:37 | 兰亭      

#3楼  回复 引用 查看   

楼主高人也。虽然现在俺不作网站,还是要收藏。
2007-09-25 08:23 | 1-2-3      

#4楼  回复 引用   

@兰亭

非常感谢你的提问。

根据我的经验,OutputCache 指令使用的就是Last-Modified报头,但却有些局限性,结合本文你可以对站点中的所有需要缓存的文件,如js/css/jpeg/gif/xml等进行自定义的客户端缓存.

再次对您表示感谢。中秋愉快!

-Lion互动网络技术中心 -Ian

本贴子以“现状”提供且没有任何担保,同时也没有授予任何权利。

为了为您创建更好的讨论环境,请时刻关注本站.
2007-09-25 08:35 | Ian[未注册用户]

#5楼  回复 引用 查看   

非常精彩哦
2007-09-25 08:39 | 大石头      

#6楼  回复 引用 查看   

支持,观望,中秋快乐:)
2007-09-25 08:52 | 老刘.      

#7楼  回复 引用   

好文章
2007-09-25 09:00 | 土人制造[未注册用户]

#8楼  回复 引用 查看   

关注,好文章。
2007-09-25 09:15 | Maple      

#9楼  回复 引用 查看   

这个方法一直在用
2007-09-25 09:28 | 远航      

#10楼  回复 引用 查看   

收藏起来,慢慢看
2007-09-25 09:40 | Clark Zheng      

#11楼  回复 引用 查看   

好文章,收藏!
2007-09-25 09:49 | 老夫子系      

#12楼  回复 引用 查看   

中秋快乐 收藏 谢谢 o(∩_∩)o...
2007-09-25 10:06 | 爱上北溟鸟      

#13楼  回复 引用   

不错不错,楼主中秋快乐
2007-09-25 10:32 | 天气预报[未注册用户]

#14楼  回复 引用   

俺不好使呢。。。

有啥要注意的事项?

#15楼  回复 引用 查看   

收藏下。
2007-09-25 10:42 | 聂锋      

#16楼  回复 引用 查看   

考虑了很久这个事情了。楼主太好了。
2007-09-25 11:37 | 暗香浮动      

#17楼  回复 引用 查看   

学习ing
感谢博主
2007-09-25 13:35 | 徐少侠      

#18楼  回复 引用 查看   

1、OutputCache 根本上说是服务器端缓存,和客户端缓存没有关系。
2、文章第一句提到“你的网站在并发访问很大并且无法承受压力的情况下,你会选择如何优化?”,客户端缓存和Http Compression并非一定能解决这类问题。

服务器无法承受可能和流量负载有关,也可能是服务器的CPU、内存和处理能力不够。
2007-09-25 14:08 | Ariel Y.      

#19楼[楼主]  回复 引用 查看   

@ken改一下作者名

不好使是什么情况?

@Ariel Y.
1、你可以监测一下OupputCache的运行状态,在缓存以后是否也是返回的304
2、你这有些太较真了,请根据标题去理解,本文主要是讲的是什么.并且在结论中也说明"如前所述,如果能正确合理的利用各种不同的缓存,他们会给你带来很多的好处",硬件方面是属于客观情况,如果你拿个386去跑网站,再牛X的人也没法优化
2007-09-25 15:15 | Lion      

#20楼  回复 引用 查看   

很久没看到好文章了,不错。高手写的文章就是不一般,有技术含量,比起首页那些OO不OO的无聊讨论好多了。
2007-09-25 16:32 | 使名扬      

#21楼  回复 引用   

对于不常修改的元素,比如图片,css,js文件等,用mod_expires直接设置缓存更方便
2007-09-25 23:32 | zhiqiang[未注册用户]

#22楼  回复 引用 查看   

个人觉得想法不错,但是客户端缓存的是什么样的内容呢?静态页面就很好判断是否被修改,如果是动态的话,仅仅是数据的改变,怎么样做呢?
2007-09-26 08:55 | jisen      

#23楼  回复 引用 查看   

 

 1protected void SendFile(OutputCSS file) 
 2
 3Response.Cookies.Clear(); 
 4Response.Clear(); 
 5
 6Response.Cache.SetRevalidation(HttpCacheRevalidation.AllCaches); 
 7
 8// 输出文件 
 9if (si != null
10
11if ((file != null&& (file.OutputData != null)) 
12
13// 客户端缓存 - 仅浏览模式 
14if (useClientCache && (currentUser.ViewMode == ViewModeEnum.LiveSite) && (ImageCache.EnableCaching)) 
15
16// 从浏览器获取最后修改日期与实体值( etag ) 
17string ifModifiedString = Request.Headers["If-Modified-Since"]; 
18if (ifModifiedString != null
19
20// IE-浏览器: 
21// If-Modified-Since: Wed, 19 Jul 2006 11:19:59 GMT; length=3350 
22DateTime ifModified; 
23if (DateTime.TryParse(ifModifiedString.Split(";".ToCharArray())[0], out ifModified)) 
24
25// 如果没有改变,让浏览器使用缓存数据 
26if (file.LastModified <= ifModified.AddSeconds(1)) 
27
28Response.StatusCode = (int)System.Net.HttpStatusCode.NotModified; 
29Response.End(); 
30return
31}
 
32}
 
33}
 
34}
 
35
36// 准备输出 
37Response.ContentType = "text/css"
38
39if (useClientCache && (currentUser.ViewMode == ViewModeEnum.LiveSite) && (ImageCache.EnableCaching)) 
40
41// 发送允许客户端缓存的最后修改的标头 
42Response.Cache.SetLastModified(file.LastModified); 
43Response.Cache.SetExpires(DateTime.Now.AddHours(24)); 
44Response.Cache.SetCacheability(HttpCacheability.Public); 
45}
 
46
47// 添加输出数据 
48Response.Write(file.OutputData); 
49}
 
50}
 
51
52//发送 
53Response.End(); 
54}
 
2007-09-26 10:02 | 远航      

#24楼  回复 引用 查看   

@Lion

1、有一点可以肯定的是,Output Cache肯定是在服务器端进行了缓存,至于是否同时使用了last-modified报头,我没有调研没有发言权。MSDN原文如下:
Page Output Cache
The page output cache stores the contents of a processed ASP.NET page in memory. This allows ASP.NET to send a page response to a client without going through the page processing lifecycle again.

2、是有些较真:-),不过还是希望大家描述最好准确些,于己提高沟通能力,于人免于误导新手。
2007-09-26 16:21 | Ariel Y.      

#25楼  回复 引用 查看   

小弟也研究过这方面的内容

初探浏览器缓存实现原理 --提高性能

浏览器缓存能解决什么问题?

asp.net服务器端缓存机制 适用范围 的介绍 --提高性能





2007-09-27 09:01 | jecray      

#26楼  回复 引用   

学习了
2007-09-27 21:56 | w[未注册用户]

#27楼  回复 引用   

收藏了

#28楼  回复 引用   

--引用--------------------------------------------------
jisen: 个人觉得想法不错,但是客户端缓存的是什么样的内容呢?静态页面就很好判断是否被修改,如果是动态的话,仅仅是数据的改变,怎么样做呢?
--------------------------------------------------------
2008-03-30 17:26 | jeanso911[未注册用户]

#29楼  回复 引用 查看   

像css,图片等文件IIS会自动设置吧,用httpwatch去抓,js,css,图片第一次请求时会加截,第二次请求时就返回304了。
2009-05-13 08:24 | ruson      

#30楼  回复 引用 查看   

这些 玩意 直接交给IIS 去处理吧
2010-05-26 15:56 | 搞IT的狐狸      

导航

<2007年9月>
2627282930311
2345678
9101112131415
16171819202122
23242526272829
30123456

公告

If you have a dream, do everything for it! If you happy, more happy for you are the happy owner!
If you want happyness, happy in learning, happy in working, and happy in life!
Feel better? Smile ! Believe that everything will be better and better!

昵称:Lion
园龄:7年7个月
粉丝:16
关注:0

搜索

 
 

常用链接

随笔分类

随笔档案

文章分类

文章档案

相册

最新评论

阅读排行榜

评论排行榜

推荐排行榜