什么是缓存
缓存是浏览器的一种机制,可以把请求过的web资源(html、css、js、图片等)拷贝一份副本存储在浏览器中,并根据请求配置选择是否使用该副本。
缓存作用
- 减少网络带宽消耗
- 降低服务器压力
- 减少网络延迟,使页面的打开速度更快,增加用户体验
根据不同的划分规则,缓存可以分为以下几种:
本文只介绍浏览器的缓存机制。
浏览器缓存规则定义位置
可以在 HTTP协议头 和HTML页面的 meta标签 中定义。
meta标签定义:
<!- Pragma 是 http1.0 版本中给客户端设定缓存方式之一 ->
<meta http-equiv="Pragma" content="no-cache">
上述代码的含义:浏览器当前页面不被缓存,每次访问都向服务器请求。
http协议头定义:
与缓存有关的消息报头有expires
,cache-control
,Last-Modified
,If-modified-since
,Etag
,If-none-match
等。
缓存分类
根据是否需要向服务器发送资源请求,分为 强缓存 和 协商缓存。
强缓存意味着强制使用缓存,协商缓存意味着每用一次缓存都要协商一次。 强缓存和协商缓存都允许使用情况下,优先强缓存。
强缓存
强缓存的控制字段:
- HTTP1.0:
Expires
- HTTP1.1 :
Cache-Control
判断过程:请求再次发起 -> 浏览器根据 expires
和 cache-control
判断目标资源是否命中"强缓存" -> 若命中,直接从缓存获取资源,不再与服务器发生通讯。
如果cache-control
与expires
同时存在,以cache-control
为主,继续使用 expires 的目的就是向下兼容。
Expire
已经被Cache-Control
替代,原因在于Expires
依赖于本地时间,它控制缓存的原理是使用客户端的时间与服务端返回的时间做对比,那么如果客户端与服务端的时间因为某些原因(例如时区不同;客户端和服务端有一方的时间不准确;用户修改了本地时间)发生误差,那么强制缓存则会直接失效。
Cache-Control取值:
在HTTP/1.1中,Cache-Control
是最重要的规则,主要用于控制网页缓存,主要取值为:
public:所有内容都将被缓存(客户端和代理服务器都可缓存)
private:所有内容只有客户端可以缓存,Cache-Control
的默认取值
no-cache:客户端缓存内容,但是是否使用缓存则需要经过协商缓存来验证决定
no-store:所有内容都不会被缓存,即不使用强制缓存,也不使用协商缓存
max-age=xxx (xxx is numeric):缓存内容将在xxx秒后失效
must-revalidate: 强制浏览器严格遵守你设置的cache规则
proxy-revalidate: 强制proxy严格遵守你设置的cache规则
强缓存流程:
协商缓存
协商缓存就是强制缓存失效后,浏览器携带缓存标识向服务器发起请求,由服务器根据缓存标识决定是否使用缓存的过程,主要有以下两种情况:
协商缓存生效,返回304 && 协商缓存失效,返回200和请求结果。
协商缓存流程:
协商缓存的控制字段:
- HTTP1.0:
Last-Modified
&&If-Modified-Since
- HTTP1.1 :
Etag
&&If-None-Match
Last-Modified 与 If-Modified-Since
Last-Modified
是服务器响应请求时,返回该资源文件在服务器最后被修改的时间
流程:
- 首次请求
- 服务器告知启用协商缓存规则,并在响应头中带上
Last-Modified
,告知缓存到期时间 - 随后的每次请求,请求头上都会携带
If-Modified-Since
,该值等于上一次响应头中的Last-Modified
的值 - 服务器收到
If-Modified-Since
后,会将该属性的值与服务器上资源的最后修改时间进行匹配,从而判断资源是否发生了变化 - 如果发生变化会返回一个完整的响应内容,在响应头中添加新的
Last-Modified
值,否则,只返回 header 部分,状态码为304,响应头不会再添加Last-Modified
弊端: Last-Modified
无法正确感知文件的变化,譬如说,文件的编辑时间修改了而内容没有修改,或者修改文件速度太快,几毫秒就改一次文件,If-Modified-Since
只能检测秒级的变化.
为了解决这个问题,Etag
作为 Last-Modified
的升级版,因时而生。Etag
是通过标识字符串来辨别文件内容是否发生修改的,文件内容不一致才会生成新的标识字符串,这就弥补了 Last-Modified
时间戳的不足,通过 Etag
可以精准的感知文件的变化。
Etag && If-None-Match
Etag
是服务器响应请求时,返回当前资源文件的一个唯一标识(由服务器生成)
流程:
- 首次请求
- 服务器启用协商缓存情况下,会在响应头中带上
Etag
- 随后每次请求,请求头上都会带上
If-None-Match
,该值等于上一次响应头中的Etag
的值 - 服务器收到
If-None-Match
后,会进行比对,从而判断资源是否发生变化 - 如果变化返回一个完整响应内容,在响应头上添加新的
Etag
值,否则返回 304,响应头不会在添加Etag
弊端: Etag
的生成需要服务器付出额外的开销,会影响服务端性能。
Etag 并不能替代 Last-Modified,只能作为 Last-Modified 的补充和强化存在,当 Etag 和 Last-Modified 同时出现时,以 Etag 为准。
整个缓存机制的流程图:
不能被缓存的请求
- HTTP信息头中包含
Cache-Control:no-cache,pragma:no-cache(HTTP1.0)
,或Cache-Control:max-age=0
等告诉浏览器不用缓存的请求 - 需要根据
Cookie
,认证信息等决定输入内容的动态请求是不能被缓存的 - 经过HTTPS安全加密的请求
- POST请求无法被缓存
- HTTP响应头中不包含
Last-Modified/Etag
,也不包含Cache-Control/Expires
的请求无法被缓存
用户操作行为与缓存
浏览器中的操作对缓存的影响
- 强制刷新 – 当按下ctrl+F5来刷新页面的时候, 浏览器将绕过各种缓存(本地缓存和协商缓存), 直接让服务器返回最新的资源
- 普通刷新 – 当按下F5来刷新页面的时候,浏览器将绕过本地缓蹲来发送请求到服务器, 此时, 协商缓存是有效的
- 回车或转向 – 当在地址栏上输入回车或者按下跳转按钮的时候, 所有缓存都生效
说明
此文是我之前复习的时候整理的,文章中的图片均是来源于网络,具体是哪几篇文章现在找不到链接了。所以参考文献这块就不列了,如果原作者看到可以联系我,将原文链接贴出。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。