原创文章,转载请注明: 转载自电商沙龙ec-shalom.com,专研电商艺术。
对缓存的概念一直不清不楚,导致在使用PHP写缓存的时候也很没感觉。这篇文章将全面介绍有关 缓存 ( 互动百科 | 维基百科 )cache以及利用PHP写缓存caching的技术。
- 什么是缓存Cache? 为什么人们要使用它?
- 缓存 Caches种类
- 缓存对网站的影响? 怎样正确地使用缓存?
- 网站缓存的工作原理
- 如何设置网站的缓存 Caches
- 设置优良的网站缓存机制方法
- 怎样写动态网站的缓存脚本
- 缓存常见问题大全
- 缓存机制的实现 - Web服务器端配置
- 缓存机制的实现:服务器端脚本
- 参考文档和深入阅读Referencing Reading
- 关于本文
什么是缓存Cache? 为什么人们要使用它?
一个使用缓存Cache的站点会监听客户端向服务器端发出的请求,并保存服务器端的回应——比如HTML页面、图片等文件。接着,如果有另外一个使用相同URL发送请求,他能够使用之前已经保存下来的反馈文件,而不是再次向服务器发出请求。
有两个主要的理由让人们使用缓存:
- 减少延迟 — 因为所发出的网页请求是指向更接近客户端的缓存而不再是源服务器端,因此请求所花费时间更短,这让网站看上去反应更快。
- 降低网络负荷 — 因为缓存文件可以重复使用,节省了不少的带宽.这也给用户省了不少流量.
缓存 Caches种类
浏览器缓存 Caches
在现代浏览器(比如IE、Chrome、Mozilla等等)都有缓存设置选项,它可以将你浏览过的网页全部保存到你本地电脑的硬盘中。当你点击浏 览器的“后退”或者曾经浏览过的页面的链接时就能使用这种缓存了,同样的,如果你在自己的网站使用导航图片,浏览器缓存也能迅速地做出反应。浏览器缓存原理机制(扩展阅读>>)如下图所示:
代理缓存 Caches
web代理缓存使用相同的原理,但却有大得多的规模,代理可以用相同的方法为几百甚至几千的使用者服务;一些大公司和ISPs通常为它们设置了防火墙,或者单独的设备。
因为代理缓存既不属于客户端也不属于服务器端,而是利用网络路由请求信息。有一种方式可以做到这一点,就是手动设置浏览器的代理。你还可以使用网页代理,网页代理将你的url请求通过它潜在的网络定向到他们,所以用户甚至无须手动配置它们。
代理缓存是共享缓存的一种,不是只有一个人正在使用它们,而是同时又大量的用户,因为他们可以非常好的节约了带宽和网页延迟。
网关缓存
就像前面提到的“反向代理缓存” 和 “代理缓存”,网关缓存同样是充当一种代理的角色,通过网络管理员(或是站长自己),可以让带宽更有效的利用,让他们的网站变得更加可靠。
Content delivery networks (CDNs) 出售他们的缓存服务. Speedera and Akamai 就是非常著名的 CDNs.
缓存对网站的影响? 怎样正确地使用缓存?
网站的缓存经常被误解,站长认为代理缓存可以“隐藏”起来,给他们的用户带去麻烦的同时,又不能及时地更新网站的内容。本教程可以让你网站的教程变 得友好起来。CDNs不像代理缓存,他们的网关服务缓存可以根据网站自行设置。另一方面,这种缓存还能加快你网站的加载速度,用户体验得到质的提高。
许多大公司花费了几百万美金在全世界的进行服务器集群来复制他们的网站内容,就是为了保证使用网站的用户能保持最快的响应速度。缓存能够为你做同样的事,甚至可以说缓存更接近终端用户,而这一切是免费的。
不管你愿不愿意,代理缓存和浏览器缓存是既存的事实。如果你不能够正确地配置你网站缓存,网站将始终保持缓存功能。
网站缓存的工作原理
所有的缓存都有一整套工作机制(当然,在缓存没有被禁止的前提下),其中一些规则来自于HTTP协议(扩展阅读>>)(HTTP 1.0 和 1.1),另一些则来自管理员(有可能是浏览器,也有可能是代理)。
通常来说,它们有一些共有的规则:
- header响应头部分可以设置了是否进行缓存.
- 如果请求是经过HTTP 认证 (HTTP AUTH扩展阅读>>)或是SSL安全链接 (i.e., HTTPS),缓存也无法工作.
- 如果符合以下条件,缓存机制的启用是通过页面的刷新引起(不需要经过检测服务器就可以直接发送到客户端):
- 时间没有超过已设置的缓存页面过期时间或者其它类似 age-controlling(指示客户机可以接收生存期不大于指定时间的响应) 的设置。
- 缓存是最近请求时保存的,或是缓存修改的时间也是新的。
- 当资源过期时(使用Cache-Control标识的max-age),发现资源具有Last-Modified(Etag)声明,则再次向web服务器请求时带上头 If-Modified-Since(If-None-Match),表示客户端请求时间。web服务器收到请求后发现有头If-Modified-Since(If-None-Match)则与被请求资源的最后修改时间进行比对。若最后修改时间较新,说明资源又被改动过,则响应整片资源内容(写在响应消息包体内),HTTP 200;若最后修改时间较旧,说明资源无新修改,则响应HTTP 304 (无需包体,节省浏览),告知浏览器继续使用所保存的cache。
- 特定情况— 比如, 与服务器断开连接 — 缓存会直接作为请求的响应.
刷新和验证都是缓存机制作用于网站内容的方式,用户行为和浏览器缓存之间的联系可参考下图:
如何设置网站的缓存 Caches
有一些工具可以帮助站长和开发人员为他们的网站设置缓存。它可能会要求配置你的服务器,更具体的内容点击这里Implementation。
HTML Meta 标签Tags vs. HTTP 报头Headers
我们可以在HTML文件中的<HEAD>部分写入tag标签来描述该文件的属性。meta tags 常常可以用来标签文件是否启用缓存和设置缓存的过期时间。Meta tags 很容易使用,但是却很没效率.那是因为他们只对浏览器部分的缓存有用,而代理缓存(代理从来不会读取HTML文件). 如果你的主机放在ISP或者集群服务器,他们讲不会给你随意写入HTTP协议的权限 (Expires
以及Cache-Control
).
另一方面,真正的 HTTP headers 是不能在 HTML文件里看到的,他们通常由Web服务器自动地生成. 即使这样,你仍然可以依据网站所在的服务器,在某种程度上控制它们。接下来,你讲发现HTTP 协议headers 十分有趣.
HTTP headers 在服务器端发送HTML之前就已经传输了, 你只能通过类似firebug之类的浏览器插件检查. 典型的 HTTP 1.1 头部响应就像下面这段代码:
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
HTML将出现在这些头部信息的下面,更多设置HTTP Headers方法Implementation点击这里.
Pragma HTTP Headers (为什么HTTP头对缓存不起作用?)
许多人相信设置一个 Pragma: no-cache
HTTP 协议可以控制缓存是否开启。这其实不是完全正确的。HTTP 协议的详细说明中并没有设置任何有关Pragma的条例,相反,Pragma请求十分有争议。虽然一部分缓存会受到此参数的影响,但大多数一点作用也没有,请使用header头协议代替它!
HTTP Header 控制缓存更新
过期HTTP 协议header是控制缓存的基本意义所在。它能够告诉所有的缓存生存时间。超过了那个时间,缓存就要去请求一次服务器来查看网页文件是否已经更新。过期时间的头部设置几乎支持所有的缓存。
大多数的网站服务器允许你有好几种的方式来设置过期头部信息。通常,允许设置一个确定的过期时间(与用户最新一次发出请求的时间做对比),或者是服务器端的最后一次修改网页文件的时间。
过期时间的头部设置尤其对生成静态的图片有好处(比如logo,按钮等)。因为他们不会有太多的改动,你能够对它们设置很长的过期时间,使得你的站 点响应更快。这种方式对更新很有规律的页面同样受用。比如,如果你更新一个新闻页面在每天6点钟左右,你就可以把过期时间设置为那个时间点,这样一来,即 使你的用户没有点击“重新加载”也能够更新缓存。
注意:
Expires
的值是HTTP协议日期,任何其它值都会被当做 已过期
缓存的时间,这就会直接导致无法进行页面缓存。HTTP协议日期是格林威治时间而不是你的本地时间。
For example:
Expires: Fri, 30 Oct 1998 14:19:41 GMT
当你要使用Expires
参数时,确保你的网站服务器时间精确,这一点非常重要。你可以用 Network Time Protocol (NTP)做到这一点。虽然Expires
过期时间的设置很有用,但是依然限制很多,首先,它涉及一个时间,网站服务器时间必须和缓存时间保持同步。另一问题就是,你很容易忘记一些已经设置了Expires
的网页,如果你没有在超过网站的过期时间之前更新 Expires
,以后的每个请求都会返回到您的Web服务器,增加负载和延迟。
HTTP Header 参数Cache-Control
HTTP 1.1 ( 互动百科 | 维基百科 ) 引入了 Cache-Control
响应头参数以给站长们更多控制网站内容的权力,同时弥补了 Expires的局限
.
Cache-Control
的参数包括:
max-age=
[单位:秒 seconds] — 设置缓存最大的有效时间. 类似于Expires
, 但是这个参数定义的是时间大小(比如:60)而不是确定的时间点.单位是[秒 seconds].s-maxage=
[单位:秒 seconds] — 类似于max-age
, 但是它只用于公享缓存 (e.g., proxy) .public
— 响应会被缓存,并且在多用户间共享。正常情况, 如果要求 HTTP 认证,响应会自动设置为 private.private
— 响应只能够作为私有的缓存(e.g., 在一个浏览器中),不能再用户间共享。no-cache
— 响应不会被缓存,而是实时向服务器端请求资源。这一点很有用,这对保证HTTP 认证能够严格地禁止缓存以保证安全性很有用(这是指页面与public结合使用的情况下).既没有牺牲缓存的效率,又能保证安全。no-store
— 在任何条件下,响应都不会被缓存,并且不会被写入到客户端的磁盘里,这也是基于安全考虑的某些敏感的响应才会使用这个。must-revalidate
— 响应在特定条件下会被重用,以满足接下来的请求,但是它必须到服务器端去验证它是不是仍然是最新的。proxy-revalidate
— 类似于must-revalidate
,但不适用于代理缓存.
For example:
Cache-Control: max-age=3600, must-revalidate
如果Cache-Control
和 Expires
同时设置, Cache-Control
优先.如果你打算使用 Cache-Control
,别忘记好好看看关于 HTTP 1.1协议的文档。【查看 References and Further Information更多相关信息>>.】
缓存的验证程序
之前我们讨论过 网站缓存是如何工作的?,我们所讨论的缓存验证指,当响应的资源做出了改变时,服务器与缓存之间的通信所使用的验证。通过这种验证,如果在本地已有一份拷贝资源,缓存就可以避免下载整个资源文件。
验证器十分重要:假如没有它,就没有更新的报头(Expires
or Cache-Control
), 缓存将无法存储响应资源.大多数的验证程序是记录了资源最后一次修改的时间(报头参数中的Last-Modified
),当缓存保存了包含参数Last-Modified
的响应资源时,它将使用一个包含参数If-Modified-Since
的请求与服务器上资源的最后修改时间做对比,以查看资源是否已作出改变。
HTTP 1.1 协议同时引入一个新的验证器,名为Etag。这种验证器拥有特殊的标示符,它来自于服务器,并且随着响应资源的改变而改变。简单点即 服务器响应时给请求URL标记,并在HTTP响应头中将其传送到客户端,在Http响应头中包含 Etag:“5d8c72a5edda8d6a:3239”标识,等于告诉客户端,你拿到的这个的资源有表示 ID:5d8c72a5edda8d6a:3239。当下次需要发Request索要同一个URI的时候,浏览器同时发出一个If-None-Match 报头(Http RequestHeader)此时包头中信息包含上次访问得到的,即Etag:“5d8c72a5edda8d6a:3239”标识:
If-None-Match:"5d8c72a5edda8d6a:3239"
这样,客户端等于Cache了两份,服务器端就会比对2者的Etag。如果If-None-Match为False,返回304(缓存读取) ,不返回200(服务器读取)。
几乎所有的缓存都是使用了 Last-Modified作为验证器,而Etag有更高的优先权。大多数的网站服务器将自动产生 ETag
及 Last-Modified
作为静态内容的验证器(i.e., files);你不需要做任何改变。但是,对于动态内容(像CGI, PHP or database sites之类)却毫无作用;你可以查看本文介绍的相关内容怎样写动态网站的缓存脚本.
设置优良的网站缓存机制方法
有很多的方法可以让你的网站缓存更加友好:
- 使用一致的 URLs — 这是使用缓存的黄金法则.如果你为不同的用户提供、或是从不同的网站采集相同的内容到不同的网站页面,请使用一条URL地址。For example,如果你一旦使用了 “/index.html” ,对于其他的 HTML 文件URL也采用相同的命名方式.
- 使用图片库 来查阅不同地方使用的图片.
- 创建缓存保存不常变动的图片和页面 ,可以把参数
Cache-Control: max-age
报头参数的值设置得大些. - 为规律更新的网页设置定时缓存, 可以设置合适的 max-age or expiration 时间参数.
- 如果一个资源(尤其是可下载文件)改变了,把它的名字也改了. 用这种方式,你可以让缓存在很长的一段时间之后才过期,并且保证提供的版本是正确的。链接到改资源的网页需要将缓存时间设置得短一些.
- 除非必要,不要随意修改文件. 如果随意修改,报头参数
Last-Modified
将始终使用最新的日期.比如,当你升级网站,不要复制整个站点; 只要移动你修改的文件即可. - 只在有必要的地方使用cookies — cookies 非常难缓存, 大多数情况也没必要缓存.如果你一定需要有cookies,将它们限制在动态页面中.
- 尽量少地使用 SSL安全协议 — 因为加密的页面将不会采用共享缓存的方式储存,尽量在需要的时候使用SSL, 并且在SSL页面尽量少用图片.
- 用 REDbot检测你的网站页面— 本教程所描述的大多数概念在使用该工具时都很有用.
怎样写动态网站的缓存脚本
默认情况下,大多数的脚本语言将不会返回验证器(Last-Modified
or ETag
响应头)或者缓存更新提示(Expires
or Cache-Control
)。同时,一些真正的脚本语言是动态的(意味着他们对每个请求返回不同的响应资源),大多数站点(像搜索引擎和数据库驱动站点)都能从缓存脚本从受益。
一般来讲,如果在间隔的时间段(不管是相差几天还是几分钟),发出相同的请求,能够复写一个脚本输出,那么它就能够缓存。如果脚本输出的内容会随着URL的改变而改变,也是可以进行缓存的;但是如果脚本输出要依赖cookies,认证等,则不能缓存。
- 写一个优良的缓存脚本的最好办法是:不管内容何时更改,都将脚本的内容输出到普通的文件中,以便网站的服务器能够想其他网页一样对待它,从而生成和使用缓存的验证器。记住只对那些已经改变的文件进行写入,这样可以让
Last-Modified
的值被保护起来. - 另一个让脚本可以缓存的方法是,设置一个有关存活时间的响应头,值设置为脚本能够使用的时间。虽然
Expires设置可以实现这一点
,但是设置Cache-Control: max-age
是最简单的, 它可以在一次请求发生后的一段时间里又发出新的请求。 - 如果你不能做到这些,你将需要让脚本生成一个验证器,然后对浏览器发出请求中的
If-Modified-Since
和/或If-None-Match
做出响应. 通过分析HTTP 头你能够做到这一点,只要在适当的时候返回304(缓存读取)响应状态即可。
小技巧:
- 如非必要,尽量不使用 POST方式. 大多数的缓存无法保持对POST方式响应,你过你想通过路径或请求(GET)发送一些信息,缓存能够在未来存贮信息。
- 除非整个内容是要呈现给完整的用户,否则不要用URL来传递用户的身份信息.
- 不要指望来自一个用户的所有请求都是从同一个主机发出的, 因为缓存经常一起产生作用.
- 设置响应头中的
Content-Length
(用于描述HTTP消息实体的传输长度). 它允许你的脚本可以在长连接通信时仍有响应,并且客户端可以通过一个TCP/IP连接请求不同的资源,而不是为一次请求的都建立一个通信.
缓存常见问题大全
哪些内容是需要设置为缓存的?
有一个很好的策略,确定出网站最多人浏览、数据量(尤其是图片)最大的部分。
我怎样用缓存让我的网页尽可能快?
大多数的缓存响应资源都设置了刷新请求时间,缓存验证可以帮助你减少查看资源是否更新的时间,但是缓存始终是需要和服务器通信来检查更新的。
我已经知道缓存的优势,但我需要为我的页面统计流量数据!
如果你必须知道页面每次被浏览的数据,你可以在页面上分类一小部分设置为不缓存,比如,将一个 1*1大小的图片放到每一个页面中,相关的响应头将包含所在页面的信息。
考虑到这样做不仅无法统计有关准确的用户数据,并且有害于网络和用户(产生无效流量,增加延迟时间),你可以考虑使用第三方统计工具 相关信息>>.
如何查看HTTP 协议头?
许多浏览器可以在页面信息中查看到 Expires
和 Last-Modified
头部参数,也可用Chrome 或是 Mozilla 的firebug查看.
如果响应更完整的响应头信息,你可以用Telnet客户端来连接网站,方法如下:
第一步:在“开始”菜单中,点击“运行”命令,输入“telnet ec-shalom.com:80”。
第二步:打开本地显示。输入你想要查看的响应头地址,比如,你想查看页面 http://ec-shalom.com/683_webfilecoding.html
GET /683_webfilecoding.html HTTP/1.1 [return] Host: ec-shalom.com [return][return]
每次看到 [return]时按下回车
; 最后要点击两次回车.它将打印所有头部信息,和响应资源,如果只需要头部信息,将GET换成HEAD 。
我的页面设置了密码保护,代理缓存会怎样处理它们呢?
默认情况下,设置了HTTP认证的页面会被当做private处理;它们将不会被共享缓存保存下来。然而,你能通过页面头部设置参数 Cache-Control来达到目的;HTTP 1.1-协议将会采用缓存.
如果你想要这个页面能够被缓存起来,但是却能够验证每一个用户,将 Cache-Control: public
和 no-cache
结合起来. 它让客户端发送的验证信息在连接数据库之前先读取了缓存内容:
Cache-Control: public, no-cache
不管怎样,尽量少地使用验证;比如,如果你页面的图片是没必要经过验证的,你就把他们放到单独的文件夹中,并且配置你的服务器不要验证它。
通过缓存浏览我的网站是否安全?
代理服务器上SSL页面不会被缓存(不推荐被缓存),所以你不必为此担心。但是,由于缓存保存了非SSL请求和从他们抓取的URL,你要意识到没有安全保护的网站,可能被不道德的管理员可能搜集用户隐私,特别是通过URL。
实际上,位于服务器和客户端之间的管理员可以搜集这类信息。特别是通过CGI脚本在通过URL传递用户名和密码的时候会有很大问题;这对泄露用户名和密码是一个很大的漏洞;
如果你初步懂得互联网的安全机制,你不会对缓存服务器有任何。
我在寻找一个包含在Web发布系统解决方案,那些是比较有缓存意识的系统?
这很难说,一般说来系统越复杂越难缓存。最差就是全动态发布并不提供校验参数;你无发缓存任何内容。可以向系统提供商的技术人员了解一下,并参考后面的实现说明。
我的图片设置了1个月后过期,但是我现在需要现在更新。
过期时间是绕不过去的,除非缓存(浏览器或者代理服务器)空间不足才会删除副本,缓存副本在过期之间会被一直使用。
最好的办法是改变它们的链接,这样,新的副本将会从源服务器上重新下载。记住:引用它们的页面本身也会被缓存。因此,使用静态图片和类似内容是很容易缓存的,而引用他们的HTML页面则要保持非常更新;
如果你希望对指定的缓存服务器重新载入一个副本,你可以强制使用“刷新”(在FireFox中在reload的时候按住shift键:就会有前面提到恶Pragma: no-cache头信息发出)。或者你可以让缓存的管理员从他们的界面中删除相应内容;
我运行一个Web托管服务,如何让我的用户发布缓存友好的网页?
如果你使用apahe,可以考虑允许他们使用.htaccess文件并提供相应的文档;
另外一方面: 你也可以考虑在各种虚拟主机上建立各种缓存策略。例如: 你可以设置一个目录 /cache-1m 专门用于存放访问1个月的访问,另外一个 /no-cache目录则被用提供不可存储副本的服务。
无论如何:对于大量用户访问还是应该用缓存。对于大网站,这方面的节约很明显(带宽和服务器负载);
我标记了一些网页是可缓存的,但是浏览器仍然每次发送请求给服务。如何强制他们保存副本?
缓存服务器并不会总保存副本并重用副本;他们只是在特定情况下会不保存并使用副本。所有的缓存服务器都回基于文件的大小,类型(例如:图片 页面),或者服务器空间的剩余来确定如何缓存。你的页面相比更热门或者更大的文件相比,并不值得缓存。
所以有些缓存服务器允许管理员根据文件类型确定缓存副本的优先级,允许某些副本被永久缓存并长期有效;
缓存机制的实现 - Web服务器端配置
一般说来,应该选择最新版本的Web服务器程序来部署。不仅因为它们包含更多利于缓存的功能,新版本往往在性能和安全性方面都有很多的改善。
Apache HTTP服务器
Apache有些可选的模块来包含这些头信息: 包括Expires和Cache-Control。 这些模块在1.2版本以上都支持;
这些模块需要和apache一起编译;虽然他们已经包含在发布版本中,但缺省并没有启用。为了确定相应模块已经被启用:找到httpd程序并运行httpd -l 它会列出可用的模块,我们需要用的模块是mod_expires和mod_headers
- 如 果这些模块不可用,你需要联系管理员,重新编译并包含这些模块。这些模块有时候通过配置文件中把注释掉的配置启用,或者在编译的时候增加-enable -module=expires和-enable-module=headers选项(在apache 1.3和以上版本)。 参考Apache发布版中的INSTALL文件;
Apache一旦启用了相应的模块,你就可以在.htaccess文件或者在服务器的access.conf文件中通过mod_expires设置副本什 么时候过期。你可设置过期从访问时间或文件修改时间开始计算,并且应用到某种文件类型上或缺省设置,参考模块的文档获得更多信息,或者遇到问题的时候向你身边的apache专家讨教。
应用Cache-Control头信息,你需要使用mod_headers,它将允许你设置任意的HTTP头信息,参考mod_headers的文档可以获得更多资料;
这里有个例子说明如何使用头信息:
- .htaccess文件允许web发布者使用命令只在配置文件中用到的命令。他影响到所在目录及其子目录;问一下你的服务器管理员确认这个功能是否启用了。
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>
- 注意: 在适当情况下mod_expires会自动计算并插入Cache-Control:max-age 头信息
Apache 2.0的配置和1.3类似,更多信息可以参考2.0的mod_expires和mod_headers文档;
Microsoft IIS服务器
Microsoft的IIS可以非常容易的设置头信息,注意:这只针对IIS 4.0服务器,并且只能在NT服务器上运行。
为网站的一个区域设置头信息,先要到管理员工具界面中,然后设置属性。选择HTTP Header选单,你会看到2个有趣的区域:启用内容过期和定制HTTP头信息。头一个设置会自动配置,第二个可以用于设置Cache-Control头信息;
设置asp页面的头信息可以参考后面的ASP章节,也可以通过ISAPI模块设置头信息,细节请参考MSDN。
Netscape/iPlanet企业服务器
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程序
CGI脚本是生成内容最流行的方式之一,你可以很容易在发送内容之前的扩展HTTP头信息;大部分CGI实现都需要你写 Content-Type头信息,例如这个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;会更简单;
这样脚本可以在被请求后缓存10分钟;这样用户如果按“后退”按钮,他们不会重新提交请求;
CGI的规范同时也允许客户端发送头信息,每个头信息都有一个‘HTTP_’的前缀;这样如果一个客户端发送一个If-Modified-Since请求,就是这样的:
参考一下cgi_buffer库,一个自动处理ETag的生成和校验的库,生成Content-Length属性和对内容进行gzip压缩。在Python脚本中也只需加入一行;
服务器端包含 Server Side Includes
SSI(经常使用.shtml扩展名)是网站发布者最早可以生成动态内容的方案。通过在页面中设置特别的标记,也成为一种嵌入HTML的脚本;
大部分SSI的实现无法设置校验器,于是无法缓存。但是Apache可以通过对特定文件的组执行权限设置实现允许用户设置那种SSI可以被缓存;结合XbitHack调整整个目录。更多文档请参考mod_include文档。
PHP
PHP是一个内建在web服务器中的服务器端脚本语言,当做为HTML嵌入式脚本,很像SSI,但是有更多的选项,PHP可以在各种Web服务器上设置为CGI模式运行,或者做为Apache的模块;
缺省PHP生成副本没有设置校验器,于是也无法缓存,但是开发者可以通过Header()函数来生成HTTP的头信息;
例如:以下代码会生成一个Cache-Control头信息,并设置为3天以后过期的Expires头信息;
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的输出;
正如你看到的:你可以手工创建HTTP日期;PHP没有为你提供专门的函数(新版本已经让这个越来越容易了,请参考PHP的日期相关函数文档),当然,最简单的还是设置Cache-Control: max-age头信息,而且对于大部分情况都比较适用;
更多信息,请参考header相关的文档;
也请参考一下cgi_buffer库,自动处理ETag的生成和校验,Content-Length生成和内容的gzip压缩,PHP脚本只需包含1行代码;
Cold Fusion
Cold Fusion是Macromedia的商业服务器端脚本引擎,并且支持多种Windows平台,Linux平台和多种Unix平台。Cold Fusion通过CFHEADER标记设置HTTP头信息相对容易。可惜的是:以下的Expires头信息的设置有些容易误导;
它并不像你想像的那样工作,因为时间(本例中为请求发起的时间)并不会被转换成一个符合HTTP时间,而且打印出副本的Cold fusion的日期/时间对象,大部分客户端会忽略或者将其转换成1970年1月1日。
但是:Cold Fusion另外提供了一套日期格式化函数, GetHttpTimeSTring. 结合DateAdd函数,就很容易设置过期时间了,这里我们设置一个Header声明副本在1个月以后过期;
你也可以使用CFHEADER标签来设置Cache-Control: max-age等其他头信息;
记住:Web服务器也会将头信息设置转给Cold Fusion(做为CGI运行的时候),检查你的服务器设置并确定你是否可以利用服务器设置代替Cold Fusion。
ASP和ASP.NET
在asp中设置HTTP头信息是:确认Response方法先于HTML内容输出前被调用,或者使用
Response.Buffer暂存输出;同样的:注意某些版本的IIS缺省设置会输出Cache-Control: private
头信息,必须声明成public才能被共享缓存服务器缓存。
IIS的ASP和其他web服务器都允许你设置HTTP头信息,例如: 设置过期时间,你可以设置Response对象的属性;
设置请求的副本在输出的指定分钟后过期,类似的:也可以设置绝对的过期时间(确认你的HTTP日期格式正确)
Cache-Control头信息可以这样设置:
在ASP.NET中,Response.Expires 已经不推荐使用了,正确的方法是通过Response.Cache设置Cache相关的头信息;
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脚本。
关于本文:
本文摘自《面向站长和网站管理员的Web缓存加速指南[翻译]》,并对部分原文进行更新和标注解释,作者邮箱 234553790@qq.com