浏览器缓存机制简介
做web开发的,浏览器缓存这东西,大家应该都比较熟悉了,简略记录下。
服务器通知浏览器缓存某个资源,有两种方式:
- 传统且常用的:是通过HttpHeaders通知浏览器,常见的Headers包括:
Expires
Cache-Control
Last-Modified/If-Modified-Since
Etag/If-None-Match
- HTML5离线缓存Cache Manifest:通过html标签的manifest属性通知浏览器
下面我们逐一说明:
1. Expires
服务器通过此消息头返回一个 Fri,11 Dec 2015 01:25:57GMT
格式的过期时间,通知浏览器在过期时间之前前浏览器可以直接从浏览器缓存取数据,而无需再次请求。此消息头为 HTTP 1.0
时期的产物。
2. Cache-Control
服务器通过此消息头通知浏览器执行相应的缓存策略,当缓存策略生效时,浏览器不会再向服务器发送请求,相比于Expire消息头,他的选择更多样化,可用值如下:
可用值形式 | 示例 | 说明 |
---|---|---|
Public | Cache-Control: public | 指示响应可被任何缓存区缓存。 |
Private | Cache-Control: private | 指示对于单个用户的整个或部分响应消息,不能被共享缓存处理。 这允许服务器仅仅描述当用户的部分响应消息,此响应消息对于其他用户的请求无效。 |
no-cache | Cache-Control: no-cache | 指示请求或响应消息不能缓存。 |
no-store | Cache-Control: public | 用于防止重要的信息被无意的发布。在请求消息中发送将使得请求和响应消息都不使用缓存。 |
max-age | Cache-Control: max-age=3600 | 指示客户机可以接收生存期不大于指定时间(以秒为单位)的响应。 |
min-fresh | Cache-Control: min-fresh=3600 | 指示客户机可以接收响应时间小于当前时间加上指定时间(以秒为单位)的响应。 |
max-stale | Cache-Control: max-stale=3600 | 指示客户机可以接收超出超时期间的响应消息。 如果指定max-stale消息的值,那么客户机可以接收超出超时期指定值之内的响应消息(以秒为单位)。 |
3. Last-Modified/If-Modified-Since
需要配合 Cache-control
来使用:Last-Modified
消息头通知客户端当前请求的资源的最后修改时间;当通过max-age
判断资源已过期,且资源具有Last-Modified
声明,则再次向服务器请求此资源时会携带 If-Modified-Since
消息头,服务器将根据头If-Modified-Since
与请求资源的最后修改时间进行比对。若资源在If-Modified-Since
时间周无修改,则响应HTTP 304
且不返回任何body,否则返回最新的资源。
4. Etag/If-None-Match
需要配合 Cache-control
来使用:服务器在响应请求时,通过Etag
告知浏览器当前资源在服务器的唯一标识;当资源过期(max-age
),且资源具有Etage声明,则再次请求该资源时将携带If-None-Match
消息头,其值为 Etag的值。服务器将会对比唯一标识是否匹配,并决定返回304或200。
大家可能会发现,其实 Last-Modified
已经很强大了,为什么还需要 Etag
呢?
其实,Etag
主要是为了解决 Last-Modified
难以解决的几个问题,可以算是 Last-Modified
的补充:
- Last-Modified只能精确到秒级,如果资源在1秒钟内被多次修改,则无法准确声明文件的修改时间
- 某些资源会被定期重新生成,虽然最后修改时间变了,但资源内容并没有什么变化时,Last-Modified会弃用缓存
5. HTML5离线缓存Cache Manifest
Cache Manifest是HTML5中引入的一种缓存机制,可以帮助构建一个web离线应用,也就是说,被Cache Manifest指定缓存的资源是不需要网络即可使用的。
Cache Manifest 使用基础:
- Cache Manifest是服务器端的一个按照指定格式书写的文本文件
- manifest文本文件需要配置 MIME-Type为
text/cache-manifest
- manifest文本文件的建议的扩展名是:
*.appcache
,但实际上你可以使用任何扩展名。 - 启用Cache Manifest时,需要在HTML文档的<html>标签中指定manifest属性,例如:
<!DOCTYPE HTML> <html manifest="demo.appcache"> ... </html>
Manifest 文件格式
manifest 文件可分为四个部分:
CACHE MANIFEST
CACHE MANIFEST必须位于文件第一行,这是一个固定格式CACHE
这是一个必需的节点,在此标题下列出的文件将在首次下载后进行缓存NETWORK
可选节点,在此标题下列出的文件需要与服务器的连接,且不会被缓存FALLBACK
可选节点,在此标题下列出的文件规定当页面无法访问时的回退页面(比如 404 页面)
下面是一个完整的manifest文件示例:
CACHE MANIFEST
# 2015-12-13 v1.0.0
CACHE:
/common.css
/logo.png
http://momo314.3000ways.com/scripts/jquery-2.1.4.min.js
/error/404.html
NETWORK:
payment.aspx
FALLBACK:
/private/ /error/404.html
下面我们分析一下上面的manifest文件:
- 第一行为
CACHE MANIFEST
- 第二行建议保留为注释行,注释行以#开始
- CACHE节点,指定缓存了3个资源文件,这3个文件在首次下载后将被缓存,后续使用时不会再从网络获取
- NETWORK节点,指定了payment.aspx页面将始终从网络获取,这也意味着在离线状态下,这个页面是不可用的
- FALLBACK节点,指定在private目录下的资源无法访问时,将使用/error/404.html来代替他
- 在缓存配置中既可以试用相对路径,也可以使用绝对路径
- NETWORK节点可以使用通配符 * 来指定所有资源都必须联网访问,如下所示:
NETWORK: *
Manifest 缓存更新
Manifest缓存的更新方式有3种:
- 直接更新manifest文件,这也是我们为什么把第二行留为注释行的原因,如果你改了一个js文件的内容,但是文件名并没有改动,可以直接修改注释行来更新缓存
- 通过javascript调用 HTML5 API
window.applicationCache.update();
来更新 - 清除浏览器缓存,不多说了,这种方法怎么都挡不住,最管用了。。。
Manifest 缓存注意事项
- 浏览器对缓存数据的容量是有限制的(某些浏览器设置的限制是每个站点 5MB),所以不要缓存太多噢。
- 如果manifest文件,或者内部列举的某一个文件不能正常下载,整个更新过程都将失败,浏览器继续全部使用老的缓存。
- 引用manifest的html必须与manifest文件同源,在同一个域下。
- FALLBACK中的资源必须和manifest文件同源。
- 当一个资源被缓存后,该浏览器直接请求这个绝对路径也会访问缓存中的资源。
- 站点中的其他页面即使没有设置manifest属性,请求的资源如果在缓存中也从缓存中访问。
- 当manifest文件发生改变时,资源请求本身也会触发更新。