原文(英文)地址: http://www.mnot.net/cache_docs/? 版权声明:署名-非商业性使用-禁止演绎 2.0 这是一篇知识性的文档,主要目的是为了让Web缓存相关概念更容易被开发者理解并应用于实际的应用环境中。为了简要起见,某些实现方面的细节被简化或省略了。如果你更关心细节实现则完全不必耐心看完本文,后面参考文档和更多深入阅读部分可能是你更需要的内容。
什么是Web缓存,为什么要使用它?Web缓存位于Web服务器之间(1个或多个,内容源服务器)和客户端之间(1个或多个):缓存会根据进来的请求保存输出内容的副本,例如html页面, 图片,文件(统称为副本),然后,当下一个请求来到的时候:如果是相同的URL,缓存直接使用副本响应访问请求,而不是向源服务器再次发送请求。使用缓存主要有2大理由:
缓存的类型浏览器缓存对于新一代的Web浏览器来说(例如:IE,Firefox):一般都能在设置对话框中发现关于缓存的设置,通过在你的电脑上僻处一块硬盘空间用于存储你已经看过的网站的副本。浏览器缓存根据非常简单的规则进行工作:在同一个会话过程中(在当前浏览器没有被关闭之前)会检查一次并确定缓存的副本足够新。这个缓存对于用户点击“后退”或者点击刚访问过的链接特别有用,如果你浏览过程中访问到同一个图片,这些图片可以从浏览器缓存中调出而即时显现。 代理服务器缓存Web代理服务器使用同样的缓存原理,只是规模更大。代理服务器群为成百上千用户服务使用同样的机制;大公司和ISP经常在他们的防火墙上假设代理缓存或者单独的缓存设备; 由于带路服务器缓存并非客户端或者源服务器的一部分,而是位于原网络之外,请求必须路由到他们才能起作用。一个方法是手工设置你的浏览器:告诉浏览器使用 那个代理,另外一个是通过中间服务器:这个中间服务器处理所有的web请求,并将请求转发到后台网络,而用户不必配置代理,甚至不必知道代理的存在; 代理服务器缓存:是一个共享缓存,不只为一个用户服务,经常为大量用户使用,因此在减少相应时间和带宽使用方面很有效:因为同一个副本会被重用多次。 网关缓存也被称为反向代理缓存或间接代理缓存,网关缓存也是一个中间服务器,和内网管理员部署缓存用于节省带宽不同:网关缓存一般是网站管理员自己部署:让他们的网站更容易扩展并获得更好的性能; Web缓存无害吗?为什么要鼓励缓存?Web缓存在互联网上最容易被误解的技术之一:网站管理员经常怕对网站失去控制,由于代理缓存会“隐藏”他们的用户,让他们感觉难以监控谁在使用他们的网站。 另外一方面:如果良好地规划了你的网站,缓存会有助于网站服务更快,并节省服务器负载和互联网的链接请求。这个改善是显著的:一个难以缓存的网站可能需要几秒去载入页面,而对比有缓存的网站页面几乎是即时显现:用户更喜欢速度快的网站并更经常的访问; 这样想:很多大型互联网公司为全世界服务器群投入上百万资金,为的就是让用户访问尽可能快,客户端缓存也是这个目的,只不过更靠近用户一端,而且最好的一点是你甚至根本不用为此付费。 事实上,无论你是否喜欢,代理服务器和浏览器都回启用缓存。如果你没有配置网站正确的缓存,他们会按照缺省或者缓存管理员的策略进行缓存。 缓存如何工作所有的缓存都用一套规则来帮助他们决定什么时候使用缓存中的副本提供服务(假设有副本可用的情况下);一些规则在协议中有定义(HTTP协议1.0和1.1),一些规则由缓存的管理员设置(浏览器的用户或者代理服务器的管理员);
? 如果副本足够新,从缓存中提取就立刻能用了; 如何控制(控制不)缓存有很多工具可以帮助设计师和网站管理员调整缓存服务器对待网站的方式,这也许需要你亲自下手对服务器的配置进行一些调整,但绝对值得;了解如何使用这些工具请参考后面的实现章节; HTML meta标签和HTTP 头信息HTML的编写者会在文档的<HEAD>区域中加入描述文档的各种属性,这些META标签常常被用于标记文档不可以被缓存或者标记多长时间后过期;
HTTP/1.1 200
OK
Date: Fri, 30 Oct 1998 13:19:41 GMT Server: Apache/1.3.3 (Unix) Cache-Control: max-age=3600, must-revalidate Expires: Fri, 30 Oct 1998 14:19:41 GMT Last-Modified: Mon, 29 Jun 1998 02:28:12 GMT ETag: "3e86-410-3596fbbc" Content-Length: 1040 Content-Type: text/html
Pragma HTTP头信息 (为什么它不起作用)很多人认为在HTTP头信息中设置了Pragma: no-cache后会让内容无法被缓存。但事实并非如此:HTTP的规范中,响应型头信息没有任何关于Pragma属性的说明,而讨论了的是请求型头信息 Pragma属性(头信息也由浏览器发送给服务器),虽然少数集中缓存服务器会遵循这个头信息,但大部分不会。用了Pragma也不起什么作用,要用就使 用下列头信息: 使用Expires(过期时间)HTTP头信息来控制保鲜期Expires(过期时间)
属性是HTTP控制缓存的基本手段,这个属性告诉缓存器:相关副本在多长时间内是新鲜的。过了这个时间,缓存器就会向源服务器发送请求,检查文档是否被修改。几乎所有的缓存服务器都支持Expires(过期时间)属性; Expires头信息:对于设置静态图片文件(例如导航栏和图片按钮)可缓存特别有用;因为这些图片修改很少,你可以给它们设置一个特别长的过期时间,这会使你的网站对用户变得相应非常快;他们对于控制有规律改变的网页也很有用,例如:你每天早上6点更新新闻页,你可以设置副本的过期时间也是这个时间,这样缓存 服务器就知道什么时候去取一个更新版本,而不必让用户去按浏览器的“刷新”按钮。 过期时间头信息属性值只能是HTTP格式的日期时间,其他的都会被解析成当前时间“之前”,副本会过期,记住:HTTP的日期时间必须是格林威治时间(GMT),而不是本地时间。举例:
Expires: Fri, 30
Oct 1998 14:19:41 GMT
所以使用过期时间属性一定要确认你的Web服务器时间设置正确,一个途径是通过网络时间同步协议(Network Time Protocol
NTP),和你的系统管理员那里你可以了解更多细节。 Cache-Control(缓存控制) HTTP头信息HTTP
1.1介绍了另外一组头信息属性:Cache-Control响应头信息,让网站的发布者可以更全面的控制他们的内容,并定位过期时间的限制。
举例: Cache-Control: max-age=3600,
must-revalidate
如果你计划试用Cache-Control属性,你应该看一下这篇HTTP文档,详见参考和深入阅读; 校验参数和校验在Web缓存如何工作:
我们说过:校验是当副本已经修改后,服务器和缓存之间的通讯机制;使用这个机制:缓存服务器可以避免副本实际上仍然足够新的情况下重复下载整个原件。 创建利于缓存网站的窍门除了使用新鲜度信息和校验,你还有很多方法使你的网站缓存友好。
编写利于缓存的脚本脚本缺省不会返回校验参数(返回Last-Modified或ETag头信息)或其他新鲜度信息(Expires或Cache-Control),有些动态脚本的确是动态内容(每次相应内容都不一样),但是更多(搜索引擎,数据库引擎网站)网站还是能从缓存友好中获益的。
其他窍门:
常见问题解答让网站变得可缓存的要点是什么?好的策略是确定那些内容最热门,大量的复制(特别是图片)并针对这些内容先部署缓存。 如何让页面通过缓存达到最快相应?缓存最好的副本是那些可以长时间保持新鲜的内容;基于校验虽然有助于加快相应,但是它不得不和源服务器联系一次去检查内容是否够新,如果缓存服务器上就知道内容是新的,内容就可以直接相应返回了。 我理解缓存是好的,但是我不得不统计多少人访问了我的网站!如果你必须知道每次页面访问的,选择【一】个页面上的小元素,或者页面本身,通过适当的头信息让其不可缓存,例如:
可以在每个页面上部署一个1x1像素的透明图片。Referer头信息会有包含这个图片的每个页面信息; 我如何能看到HTTP头信息的内容?很多浏览器在页面属性或类似界面中可以让你看到Expires
和Last-Modified信息;如果有的话:你会找到页面信息的菜单和页面相关的文件(如图片),并且包含他们的详细信息;
GET /foo.html
HTTP/1.1 [回车]
GET /foo.html HTTP/1.1 [return] Host: www.example.com [回车][回车] Host: www.example.com [return][return] 在[回车]处按键盘的回车键;在最后,要按2次回车,然后,就会输出头信息及完整页面,如果只想看头信息,将GET换成HEAD。 我的页面是密码保护的,代理缓存服务器如何处理他们?缺省的,网页被HTTP认证保护的都是私密内容,它们不会被任何共享缓存保留。但是,你可以通过设置Cache-Control:
public让认证页面可缓存,HTTP
1.1标准兼容的缓存服务器会认出它们可缓存。 Cache-Control: public, no-cache 无论如何:这是减少认证请求的最好方法,例如: 你的图片是不机密的,将它们部署在另外一个目录,并对此配置服务器不强制认证。这样,那些图片会缺省都缓存。 我们是否要担心用户通过cache访问我的站点?代理服务器上SSL页面不会被缓存(不推荐被缓存),所以你不必为此担心。但是,由于缓存保存了非SSL请求和从他们抓取的URL,你要意识到没有安全保护的网站,可能被不道德的管理员可能搜集用户隐私,特别是通过URL。 我在寻找一个包含在Web发布系统解决方案,那些是比较有缓存意识的系统?这很难说,一般说来系统越复杂越难缓存。最差就是全动态发布并不提供校验参数;你无发缓存任何内容。可以向系统提供商的技术人员了解一下,并参考后面的实现说明。 我的图片设置了1个月后过期,但是我现在需要现在更新。过期时间是绕不过去的,除非缓存(浏览器或者代理服务器)空间不足才会删除副本,缓存副本在过期之间会被一直使用。 我运行一个Web托管服务,如何让我的用户发布缓存友好的网页?如果你使用apahe,可以考虑允许他们使用.htaccess文件并提供相应的文档; 我标记了一些网页是可缓存的,但是浏览器仍然每次发送请求给服务。如何强制他们保存副本?缓存服务器并不会总保存副本并重用副本;他们只是在特定情况下会不保存并使用副本。所有的缓存服务器都回基于文件的大小,类型(例如:图片
页面),或者服务器空间的剩余来确定如何缓存。你的页面相比更热门或者更大的文件相比,并不值得缓存。 缓存机制的实现 - Web服务器端配置一般说来,应该选择最新版本的Web服务器程序来部署。不仅因为它们包含更多利于缓存的功能,新版本往往在性能和安全性方面都有很多的改善。 Apache HTTP服务器Apache有些可选的模块来包含这些头信息: 包括Expires和Cache-Control。
这些模块在1.2版本以上都支持;
Apache一旦启用了相应的模块,你就可以在.htaccess文件或者在服务器的access.conf文件中通过mod_expires设置副本什
么时候过期。你可设置过期从访问时间或文件修改时间开始计算,并且应用到某种文件类型上或缺省设置,参考模块的文档获得更多信息,或者遇到问题的时候向你身边的apache专家讨教。
### 启用
mod_expires
ExpiresActive On ### 设置 .gif 在被访问过后1个月过期。 ExpiresByType image/gif A2592000 ### 其他文件设置为最后修改时间1天后过期 ### (用了另外的语法) ExpiresDefault "modification plus 1 day" ### 在index.html文件应用 Cache-Control头属性 <Files index.html> Header append Cache-Control "public, must-revalidate" </Files>???????
Apache 2.0的配置和1.3类似,更多信息可以参考2.0的mod_expires和mod_headers文档; Microsoft IIS服务器Microsoft的IIS可以非常容易的设置头信息,注意:这只针对IIS
4.0服务器,并且只能在NT服务器上运行。 Netscape/iPlanet企业服务器3.6版本以后,Netscape/iPlanet已经不能设置Expires头信息了,他从3.0版本开始支持HTTP 1.1的功能。这意味着HTTP
1.1的缓存(代理服务器/浏览器)优势都可以通过你对Cache-Control设置来获得。 缓存机制的实现:服务器端脚本需要注意的一点是:也许服务器设置HTTP头信息比脚本语言更容易,但是两者你都应该使用。 CGI程序CGI脚本是生成内容最流行的方式之一,你可以很容易在发送内容之前的扩展HTTP头信息;大部分CGI实现都需要你写 Content-Type头信息,例如这个Perl脚本:
#!/usr/bin/perl
print "Content-type: text/html\n"; print "Expires: Thu, 29 Oct 1998 17:04:19 GMT\n"; print "\n"; ### 后面是内容体... 由于都是文本,你可以很容易通过内置函数生成Expires和其他日期相关的头信息。如果你使用Cache-Control: max-age;会更简单;
print
"Cache-Control: max-age=600\n";
这样脚本可以在被请求后缓存10分钟;这样用户如果按“后退”按钮,他们不会重新提交请求; HTTP_IF_MODIFIED_SINCE = Fri,
30 Oct 1998 14:19:41 GMT
服务器端包含 Server Side IncludesSSI(经常使用.shtml扩展名)是网站发布者最早可以生成动态内容的方案。通过在页面中设置特别的标记,也成为一种嵌入HTML的脚本; PHPPHP是一个内建在web服务器中的服务器端脚本语言,当做为HTML嵌入式脚本,很像SSI,但是有更多的选项,PHP可以在各种Web服务器上设置为CGI模式运行,或者做为Apache的模块;
<?php
?Header("Cache-Control: must-revalidate"); ?$offset = 60 * 60 * 24 * 3; ?$ExpStr = "Expires: " . gmdate("D, d M Y H:i:s", time() + $offset) . " GMT"; ?Header($ExpStr); ?> 记住:
Header()的输出必须先于所有其他HTML的输出; Cold FusionCold Fusion是Macromedia的商业服务器端脚本引擎,并且支持多种Windows平台,Linux平台和多种Unix平台。Cold Fusion通过CFHEADER标记设置HTTP头信息相对容易。可惜的是:以下的Expires头信息的设置有些容易误导;
<CFHEADER
NAME="Expires" VALUE="#Now()#">
它并不像你想像的那样工作,因为时间(本例中为请求发起的时间)并不会被转换成一个符合HTTP时间,而且打印出副本的Cold
fusion的日期/时间对象,大部分客户端会忽略或者将其转换成1970年1月1日。
<cfheader
name="Expires" value="#GetHttpTimeString(DateAdd('m', 1,
Now()))#">
你也可以使用CFHEADER标签来设置Cache-Control: max-age等其他头信息; ASP和ASP.NET在asp中设置HTTP头信息是:确认Response方法先于HTML内容输出前被调用,或者使用
Response.Buffer暂存输出;同样的:注意某些版本的IIS缺省设置会输出Cache-Control: private
头信息,必须声明成public才能被共享缓存服务器缓存。
<%
Response.Expires=1440 %>
设置请求的副本在输出的指定分钟后过期,类似的:也可以设置绝对的过期时间(确认你的HTTP日期格式正确)
<%
Response.ExpiresAbsolute=#May 31,1996 13:30:15 GMT# %>
Cache-Control头信息可以这样设置: <%
Response.CacheControl="public" %>
在ASP.NET中,Response.Expires 已经不推荐使用了,正确的方法是通过Response.Cache设置Cache相关的头信息;
Response.Cache.SetExpires ( DateTime.Now.AddMinutes (
60 ) ) ;
Response.Cache.SetCacheability ( HttpCacheability.Public ) ; 参考MSDN文档可以找到更多相关新年系; 参考文档和深入阅读HTTP 1.1 规范定义HTTP 1.1的规范有大量的扩展用于页面缓存,以及权威的接口实现指南,参考章节:13, 14.9, 14.21, 以及
14.25. Web-Caching.com非常精彩的介绍缓存相关概念,并介绍其他在线资源。 关于非连续性访问统计Jeff Goldberg内容丰富的演说告诉你为什么不应该过度依赖访问统计和计数器; 可缓存性检测引擎可缓存的引擎设计,检测网页并确定其如何与Web缓存服务器交互, 这个引擎配合这篇指南是一个很好的调试工具, cgi_buffer库包含库:用于CGI模式运行的Perl/Python/PHP脚本,自动处理ETag生成/校验,Content-Length生成和内容压缩。正确地。
Python版本也被用作其他大量的CGI脚本。 关于本文档本文版权属于Mark Nottingham <mnot@pobox.com>,本作品遵循创作共用版权。 |
?