前端缓存可分为两大类:HTTP 缓存和浏览器缓存。
HTTP 缓存主要是后端设置;浏览器缓存是前端设置。
HTTP 缓存指的是当客户端向服务器请求资源时,如果浏览器已经有要请求的资源的副本,就拦截请求,直接返回资源的副本,而不会再去向服务器请求资源。
常见的 HTTP 缓存只能缓存 GET 请求响应的资源,对于其他类型的响应则无能为力。
HTTP 缓存都是从第二次请求开始的。第一次请求资源时,服务器返回资源,并在响应头中回传资源的缓存参数;第二次请求时,浏览器判断这些请求参数,命中强缓存就直接 200;否则就把请求参数加到请求头中传给服务器,看是否命中协商缓存,命中则返回 304;否则服务器会返回新的资源。
使用 HTTP 缓存的原因:
- 减少了冗余的数据传输,节省了网费。
- 缓解了服务器端的压力。
- 加快了客户端加载网页的速度,大大提高了网站的性能。
HTTP 缓存的分类:
强制缓存和协商缓存:
根据是否需要重新向服务器发起请求来分类,可分为强制缓存和协商缓存。强制缓存如果生效,不需要再和服务器发生交互;而协商缓存不管是否生效,都需要和服务器发生交互。
强制缓存:
强制缓存:在缓存数据未失效的情况下,直接使用浏览器的缓存数据,不会再向服务器发送任何请求。强制缓存生效时,HTTP 的状态码为 200。
这种方式页面的加载速度是最快的,性能也是很好的,但是如果在这期间,服务器端的资源修改了,页面上是拿不到的,因为它不会再向服务器发请求了。
跟强制缓存相关的头属性有 Expires 和 Cache-Control
,用来表示资源的缓存时间。
- Expires:响应头的缓存字段。表示资源的过期时间,由服务器返回。如果时间没过期,不发起请求,直接使用本地缓存;如果时间过期,发起请求。
Cache-Control
:请求头/响应头的缓存字段。
常见的属性值有:no-store
:所有内容都不缓存;no-cache
:缓存,但是浏览器使用缓存前,都会请求服务器判断缓存资源是否是最新。max-age
:单位秒,请求资源后的 xx 秒内不再发起请求。s-maxage
:单位秒,代理服务器请求源站资源后的 xx 秒内不再发起请求,只对 CDN 有效。- public:客户端和代理服务器(CDN)都可缓存。
- private:只有客户端可以缓存。
HTTP 1.1 引入了 Cache-Control
头来克服 HTTP1.0 中的 Expires 头的限制。因为 Expires 头使用一个特定的时间,它要求服务器和客户端的时钟严格同步;另外,过期日期需要经常检查,并且一旦未来这一天到来了,还需要再服务器配置中提供一个新的日期。Cache-Control
使用 max-age
指令指定组件被缓存多久,它以秒为单位定义了一个更新窗,如果从组件被请求开始过去的秒数少于 max-age,浏览器就使用缓存的版本。两者同时存在的话,Cache-Control
优先级高于 Expires。
协商缓存:
协商缓存:在强制缓存失效后,服务器会携带标识去请示服务器是否可以继续使用缓存。如果资源未更新,服务器同意使用缓存,则返回 304,浏览器使用缓存;如果资源已经更新,服务端不同意使用缓存,则会将更新的资源和标识返回给浏览器并返回 200。
- 当浏览器第一次向服务器发送请求,服务器返回响应时,会在响应头返回协商缓存的头属性: ETag 和
Last-Modified
。ETag 标识该资源,Last-Modified
标识该资源的最新修改时间。 - 当浏览器第二次向服务器发送请求时,会在请求头中带上
If-Not-Match
和If-Modified-Since
。 - 服务器在接收到这两个参数后会做比较,会优先验证
If-Not-Match
的值是否与 ETag 一致。如果不一致,说明资源发生了更新,服务器直接返回新的资源和 200 状态码;如果一致,继续对比If-Modified-Since
与Last-Modified
;如果不一致,说明资源发生了更新,服务器直接返回新的资源和 200 状态码;如果一致,说明请求的资源没有修改,返回 304 状态码,浏览器直接在缓存中读取数据。
跟协商缓存相关的头属性有 Last-Modified
/If-Modified-Since
、ETag/If-Not-Match
,请求头和响应头需要成对出现。
Last-Modefied
: 响应头的缓存字段。资源最新修改时间。if-Modified-Since
:请求头的缓存字段。告知服务器如果在If-Modified-Since
字段指定的日期时间后,服务器上的资源发生了更新,服务器会接受请求;反之,返回 304 状态码 。和
Last-Modefied
是一对,它两会进行对比,其实就是上次服务器给的Last-Modified
,请求又还给服务器对比。- Etag:响应头的缓存字段。资源标识。
if-None-Match
:请求头的缓存字段。当If-None-Match
字段值与请求资源的 ETag 不一致时,它就告知服务器处理该请求。和 Etag 是一对,它两会进行对比。其实就是上次服务器给的 Etag,请求又还给服务器对比。
浏览器会根据响应头,在后续请求中自动携带
if-Modified-Since
、if-None-Match
等请求头。
HTTP1.1 中 Etag 的出现主要是为了解决几个 Last-Modified
比较难解决的问题:
Last-Modified
标注的最新修改时间只能精确到秒,如果某些文件在 1 秒以内被多次修改的话,它将不能准确标注文件的修改时间。- 如果某些文件是被定期生成的话,内容没有任何改变,但
Last-Modified
却变了,导致文件无法再使用缓存。 - 有可能存在服务器没有准确获取文件修改时间,或者与代理服务器时间不一致等情形。
- ETag 是服务器自动生成或者由开发者生成的对应资源在服务器端的唯一标识,ETag 可以保证每一个资源是唯一的,资源变化都会导致 ETag 变化,ETag 值的变更则说明资源状态已经被修改,ETag能够更加准确地控制缓存。
私有缓存和共享缓存:
根据是否可以被单个或者多个用户使用来分类,可分为私有缓存和共享缓存。
私有缓存(浏览器级缓存):
私有缓存只能用于单独的用户。Cache-Control: Private
。
共享缓存(代理级缓存):
共享缓存可以被多个用户使用。 Cache-Control: Public
。
使用 HTTP 缓存的方法:
静态的 HTML 页面想要设置缓存的话,可以通过 <meta>
标签设置 expires 和cache-control
。
<meta http-equiv="Cache-Control" content="max-age=7200" />
<meta http-equiv="Expires" content="Mon, 20 Jul 2013 23:00:00 GMT" />