缓存网页或者其他网络资源(图片,脚本,样式表,等)的好处是显而易见的:
减少网络带宽不仅意味着访问速度的提高,在当网络带宽不是完全免费的情况下,也有着显而易见的好处。
在HTTP/1.1的RFC中,也提到通过适当使用缓存,可以:
eliminate the need to send requests:避免了不必要的请求,从而增加访问速度
eliminate the need to send full responses:减少了响应的数据量,从而减少带宽
HTTP协议中定义了三种类型的缓存机制:
Expires
和Cache-Control
Last-Modified
和 ETag
指定内容的过期时间是最简单的实现客户端浏览器缓存的方法。Expires
指定一个时间,告诉浏览器相应的内容在指定时间之前都不会发生变化。浏览器因此也就不需要重新请求文档内容,只需从缓存中读取相应内容就可以了。
一个 Exprires 响应头看起来如下:
Expires: Thu, 19 Nov 1981 08:52:00 GMT
如果不希望浏览器缓存当前内容,可以把Expires设置为一个过去的时间。
但是Expires
有着一些明显的缺点:
Expires
值,并且无法通知客户端更新内容HTTP1.1 中引入了 Cache-Control
字段来实现对缓存的更多控制。Cache-Control
的值是一组逗号分隔的属性值。
字段 | 说明 |
---|---|
max-age=[seconds] | 相当于Expires字段,用间隔时间而不是绝对时间 |
s-maxage=[seconds] | 和 max-age类似,影响代理服务器(proxy)之类的客户端 |
public | 允许任何客户端进行缓存,包括代理服务器之类面向多个用户的 |
private | 只允许浏览器这样的单一用户使用的客户端缓存 |
no-cache | 不允许缓存 |
no-store | 不允许缓存,也不允许存储在磁盘上。出于安全考虑 |
must-revalidate | 必须向服务器验证缓存内容的freshness |
proxy-revalidate | 和 must-revalidate 类似,不过只用于 proxy cache |
Cache-Control
相应看起来可能如下:
Cache-Control: max-age=3600, must-revalidate
Last-Modified
相应头指定一个时间,告诉浏览器当前文档最后修改时间。浏览器下次访问该文档时会包含一个 If-Modified-Since
字段,目的是告诉服务器,只有请求文档的最后更新时间大于指定时间时,才需要服务器重新传送文档内容。 If-Modified-Since
的值来自浏览器收到的Last-Modified
值。
如果服务器不需要重新传送文档内容,只需返回相应头 304 Not Modified
就可以了。
Last-Modified
和If-Modified-Since
的样子看起来如下:
# 服务器 => 客户端 Last-Modified: Mon, 14 Feb 2011 10:04:00 GMT #客户端 => 服务器 If-Modified-Since: Mon, 14 Feb 2011 10:04:00 GMT
ETag
和 If-None-Match
与Last-Modified 和 If-Modified-Since的机制类似, 不同的是字段值用的不是时间而是一个字符串签名。字符串的值可以是任意值,比如文档内容的md5校验值或者其他。
举例如下:
# 服务器 => 客户端 Etag: "52e6e5972cf66ab866851c59c9900278" #客户端 => 服务器 If-None-Match: "52e6e5972cf66ab866851c59c9900278"
TODO
<meta http-equiv=”Expires” content=” Fri, 30 Oct 1998 14:19:41″> <meta http-equiv=”Cache-Control” content=”no-cache”>
作用类似于HTTP相应头,但不建议这么做。
如果要禁止各种缓存,在PHP中可以设置如下header:
header("Expires: Sun, 1 Jan 2000 12:00:00 GMT"); header("Last-Modified: " . gmdate("D, d M Y H:i:s") . "GMT"); header("Cache-Control: no-store, no-cache, must-revalidate"); header("Cache-Control: post-check=0, pre-check=0", false); header("Pragma: no-cache");