面向站长和网站管理员的Web缓存加速指南[翻译](转)
?
脚本缺省不会返回校验参数(返回Last-Modified或ETag头信息)或其他新鲜度信息(Expires或Cache-Control),有些动 态脚本的确是动态内容(每次相应内容都不一样),但是更多(搜索引擎,数据库引擎网站)网站还是能从缓存友好中获益的.
一般说来,如果脚本生成的输出在未来一段时间(几分钟或者几天)都是可重复复制的,那么就是可缓存的.如果脚本输出内容只随URL变化而变化,也是可缓存的;但如果输出会根据cookie,认证信息或者其他外部条件变化,则还是不可缓存的.
其他窍门:
具体定义请参考实现章节.
好的策略是确定那些内容最热门,大量的复制(特别是图片)并针对这些内容先部署缓存.
缓存最好的副本是那些可以长时间保持新鲜的内容;基于校验虽然有助于加快相应,但是它不得不和源服务器联系一次去检查内容是否够新,如果缓存服务器上就知道内容是新的,内容就可以直接相应返回了.
如果你必须知道每次页面访问的,选择【一】个页面上的小元素,或者页面本身,通过适当的头信息让其不可缓存,例如: 可以在每个页面上部署一个1×1像素的透明图片.Referer头信息会有包含这个图片的每个页面信息;
明确一点:这个并不会给你一个关于你用户精确度很高的统计,而且这对互联网和你的用户这都不太好,消耗了额外的带宽,强迫用户去访问无法缓存的内容.了解更多信息,参考访问统计资料.
很多浏览器在页面属性或类似界面中可以让你看到Expires 和Last-Modified信息;如果有的话:你会找到页面信息的菜单和页面相关的文件(如图片),并且包含他们的详细信息;
看到完整的头信息,你可以用telnet手工连接到Web服务器;
为此:你可能需要用一个字段指定端口(缺省是80),或者链接到www.example.com:80 或者 www.example.com 80(注意是空格),更多设置请参考一下telnet客户端的文档;
打开网站链接:请求一个查看链接,如果你想看到http://www.example.com/foo.html 连接到www.example.com的80端口后,键入:
在[回车]处按键盘的回车键;在最后,要按2次回车,然后,就会输出头信息及完整页面,如果只想看头信息,将GET换成HEAD.
缺省的,网页被HTTP认证保护的都是私密内容,它们不会被任何共享缓存保留.但是,你可以通过设置Cache-Control: public让认证页面可缓存,HTTP 1.1标准兼容的缓存服务器会认出它们可缓存.
如果你认为这些可缓存的页面,但是需要每个用户认证后才能看,可以组合使用Cache-Control: public和no-cache头信息,高速缓存必须在提供副本之前,将将新客户的认证信息提交给源服务器.设置就是这样:
Cache-Control: public, no-cache
无论如何:这是减少认证请求的最好方法,例如: 你的图片是不机密的,将它们部署在另外一个目录,并对此配置服务器不强制认证.这样,那些图片会缺省都缓存.
代理服务器上SSL页面不会被缓存(不推荐被缓存),所以你不必为此担心.但是,由于缓存保存了非SSL请求和从他们抓取的URL,你要意识到没有安全保护的网站,可能被不道德的管理员可能搜集用户隐私,特别是通过URL.
实际上,位于服务器和客户端之间的管理员可以搜集这类信息.特别是通过CGI脚本在通过URL传递用户名和密码的时候会有很大问题;这对泄露用户名和密码是一个很大的漏洞;
如果你初步懂得互联网的安全机制,你不会对缓存服务器有任何.
这很难说,一般说来系统越复杂越难缓存.最差就是全动态发布并不提供校验参数;你无发缓存任何内容.可以向系统提供商的技术人员了解一下,并参考后面的实现说明.
过期时间是绕不过去的,除非缓存(浏览器或者代理服务器)空间不足才会删除副本,缓存副本在过期之间会被一直使用.
最好的办法是改变它们的链接,这样,新的副本将会从源服务器上重新下载.记住:引用它们的页面本身也会被缓存.因此,使用静态图片和类似内容是很容易缓存的,而引用他们的HTML页面则要保持非常更新;
如果你希望对指定的缓存服务器重新载入一个副本,你可以强制使用“刷新”(在FireFox中在reload的时候按住shift键:就会有前面提到恶Pragma: no-cache头信息发出).或者你可以让缓存的管理员从他们的界面中删除相应内容;
如果你使用apahe,可以考虑允许他们使用.htaccess文件并提供相应的文档;
另外一方面: 你也可以考虑在各种虚拟主机上建立各种缓存策略.例如: 你可以设置一个目录 /cache-1m 专门用于存放访问1个月的访问,另外一个 /no-cache目录则被用提供不可存储副本的服务.
无论如何:对于大量用户访问还是应该用缓存.对于大网站,这方面的节约很明显(带宽和服务器负载);
缓存服务器并不会总保存副本并重用副本;他们只是在特定情况下会不保存并使用副本.所有的缓存服务器都回基于文件的大小,类型(例如:图片 页面),或者服务器空间的剩余来确定如何缓存.你的页面相比更热门或者更大的文件相比,并不值得缓存.
所以有些缓存服务器允许管理员根据文件类型确定缓存副本的优先级,允许某些副本被永久缓存并长期有效;
一般说来,应该选择最新版本的Web服务器程序来部署.不仅因为它们包含更多利于缓存的功能,新版本往往在性能和安全性方面都有很多的改善.
Apache有些可选的模块来包含这些头信息: 包括Expires和Cache-Control. 这些模块在1.2版本以上都支持;
这些模块需要和apache一起编译;虽然他们已经包含在发布版本中,但缺省并没有启用.为了确定相应模块已经被启用:找到httpd程序并运行httpd -l 它会列出可用的模块,我们需要用的模块是mod_expires和mod_headers
Apache一旦启用了相应的模块,你就可以在.htaccess文件或者在服务器的access.conf文件中通过mod_expires设置副本什 么时候过期.你可设置过期从访问时间或文件修改时间开始计算,并且应用到某种文件类型上或缺省设置,参考模块的文档获得更多信息,或者遇到问题的时候向你身边的apache专家讨教.
应用Cache-Control头信息,你需要使用mod_headers,它将允许你设置任意的HTTP头信息,参考mod_headers的文档可以获得更多资料;
这里有个例子说明如何使用头信息:
Apache 2.0的配置和1.3类似,更多信息可以参考2.0的mod_expires和mod_headers文档;
Microsoft的IIS可以非常容易的设置头信息,注意:这只针对IIS 4.0服务器,并且只能在NT服务器上运行.
为网站的一个区域设置头信息,先要到管理员工具界面中,然后设置属性.选择HTTP Header选单,你会看到2个有趣的区域:启用内容过期和定制HTTP头信息.头一个设置会自动配置,第二个可以用于设置Cache-Control头信息;
设置asp页面的头信息可以参考后面的ASP章节,也可以通过ISAPI模块设置头信息,细节请参考MSDN.
3.6版本以后,Netscape/iPlanet已经不能设置Expires头信息了,他从3.0版本开始支持HTTP 1.1的功能.这意味着HTTP 1.1的缓存(代理服务器/浏览器)优势都可以通过你对Cache-Control设置来获得.
使用Cache-Control头信息,在管理服务器上选择内容管理|缓存设置目录.然后:使用资源选择器,选择你希望设置头信息的目录.设置完头信息后,点击“OK”.更多信息请参考Netscape/iPlanet企业服务器的手册.
需要注意的一点是:也许服务器设置HTTP头信息比脚本语言更容易,但是两者你都应该使用.
因为服务器端的脚本主要是为了动态内容,他本身不产生可缓存的文件页面,即使内容实际是可以缓存的.如果你的内容经常改变,但是不是每次页面请求都改变, 考虑设置一个Cache-Control: max-age头信息;大部分用户会在短时间内多次访问同一页面.例如: 用户点击“后退”按钮,即使没有新内容,他们仍然要再次从服务器下载内容查看.
CGI脚本是生成内容最流行的方式之一,你可以很容易在发送内容之前的扩展HTTP头信息;大部分CGI实现都需要你写 Content-Type头信息,例如这个Perl脚本:
#!/usr/bin/perl由于都是文本,你可以很容易通过内置函数生成Expires和其他日期相关的头信息.如果你使用Cache-Control: max-age;会更简单;
print "Cache-Control: max-age=600\n";这样脚本可以在被请求后缓存10分钟;这样用户如果按“后退”按钮,他们不会重新提交请求;
CGI的规范同时也允许客户端发送头信息,每个头信息都有一个‘HTTP_’的前缀;这样如果一个客户端发送一个If-Modified-Since请求,就是这样的:
参考一下cgi_buffer库,一个自动处理ETag的生成和校验的库,生成Content-Length属性和对内容进行gzip压缩.在Python脚本中也只需加入一行;
SSI(经常使用.shtml扩展名)是网站发布者最早可以生成动态内容的方案.通过在页面中设置特别的标记,也成为一种嵌入HTML的脚本;
大部分SSI的实现无法设置校验器,于是无法缓存.但是Apache可以通过对特定文件的组执行权限设置实现允许用户设置那种SSI可以被缓存;结合XbitHack调整整个目录.更多文档请参考mod_include文档.
PHP是一个内建在web服务器中的服务器端脚本语言,当做为HTML嵌入式脚本,很像SSI,但是有更多的选项,PHP可以在各种Web服务器上设置为CGI模式运行,或者做为Apache的模块;
缺省PHP生成副本没有设置校验器,于是也无法缓存,但是开发者可以通过Header()函数来生成HTTP的头信息;
例如:以下代码会生成一个Cache-Control头信息,并设置为3天以后过期的Expires头信息;
?
?$offset = 60 * 60 * 24 * 3;
?$ExpStr = "Expires: " . gmdate("D, d M Y H:i:s", time() + $offset) . " GMT";
?Header($ExpStr);
?>
记住: Header()的输出必须先于所有其他HTML的输出;
正如你看到的:你可以手工创建HTTP日期;PHP没有为你提供专门的函数(新版本已经让这个越来越容易了,请参考PHP的日期相关函数文档),当然,最简单的还是设置Cache-Control: max-age头信息,而且对于大部分情况都比较适用;
更多信息,请参考header相关的文档;
也请参考一下cgi_buffer库,自动处理ETag的生成和校验,Content-Length生成和内容的gzip压缩,PHP脚本只需包含1行代码;
Cold Fusion是Macromedia的商业服务器端脚本引擎,并且支持多种Windows平台,Linux平台和多种Unix平台.Cold Fusion通过CFHEADER标记设置HTTP头信息相对容易.可惜的是:以下的Expires头信息的设置有些容易误导;
<CFHEADER NAME="Expires" VALUE="#Now()#">它并不像你想像的那样工作,因为时间(本例中为请求发起的时间)并不会被转换成一个符合HTTP时间,而且打印出副本的Cold fusion的日期/时间对象,大部分客户端会忽略或者将其转换成1970年1月1日.
但是:Cold Fusion另外提供了一套日期格式化函数, GetHttpTimeSTring. 结合DateAdd函数,就很容易设置过期时间了,这里我们设置一个Header声明副本在1个月以后过期;
你也可以使用CFHEADER标签来设置Cache-Control: max-age等其他头信息;
记住:Web服务器也会将头信息设置转给Cold Fusion(做为CGI运行的时候),检查你的服务器设置并确定你是否可以利用服务器设置代替Cold Fusion.
在asp中设置HTTP头信息是:确认Response方法先于HTML内容输出前被调用,或者使用 Response.Buffer暂存输出;同样的:注意某些版本的IIS缺省设置会输出Cache-Control: private 头信息,必须声明成public才能被共享缓存服务器缓存.
IIS的ASP和其他web服务器都允许你设置HTTP头信息,例如: 设置过期时间,你可以设置Response对象的属性;
设置请求的副本在输出的指定分钟后过期,类似的:也可以设置绝对的过期时间(确认你的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 ) ) ;参考MSDN文档可以找到更多相关新年系;
HTTP 1.1的规范有大量的扩展用于页面缓存,以及权威的接口实现指南,参考章节:13, 14.9, 14.21, 以及 14.25.
非常精彩的介绍缓存相关概念,并介绍其他在线资源.
Jeff Goldberg内容丰富的演说告诉你为什么不应该过度依赖访问统计和计数器;
可缓存的引擎设计,检测网页并确定其如何与Web缓存服务器交互, 这个引擎配合这篇指南是一个很好的调试工具,
包含库:用于CGI模式运行的Perl/Python/PHP脚本,自动处理ETag生成/校验,Content-Length生成和内容压缩.正确地. Python版本也被用作其他大量的CGI脚本.
本文版权属于Mark Nottingham <mnot@pobox.com>,本作品遵循创作共用版权.
如果你镜像本文,请通过以上邮件告知,这样你可以在更新时被通知;
所有的商标属于其所有人.
虽然作者确信内容在发布时的正确性,但不保证其应用或引申应用的正确性,如有误传,错误或其他需要澄清的问题请尽快告知作者;
本文最新版本可以从?http://www.mnot.net/cache_docs/?获得;
翻译版本包括:?捷克语版,法语版和中文版.
版本: 1.81 – 2007年3月16日
创作共用版权声明
翻译:?车东?2007年9月6日