详解Http缓存机制

作者:JAY 2019-05-27

前言

Web的缓存可以粗略分为两种:服务器缓存和浏览器缓存。服务器缓存(如代理服务器缓存、CDN等)让资源加载得更快,可有效提高第一次访问的加载速度;而浏览器缓存可以跳过请求重复的资源,大幅度提高第二次访问的加载速度。

浏览器缓存又可以粗略分为两种:localstorageindexDBCache等功能可以实现对特定资源和数据的储存,需要在业务层编写代码去实现缓存功能;Http协议缓存通过http header里的若干字段控制,浏览器自动判断是否使用或缓存,不需要前端业务代码参与。


本文只讨论http协议的缓存机制。服务器在Http返回的header中带上Expires、Cache-Control、Last-Modified、Etag等字段,浏览器把返回的资源或数据缓存到本地。下次需要用到相同资源的时候,通过这些字段来判断是直接从缓存中获取数据,还是重新发起请求。


强制缓存

使用http response header中的Expires和Cache-Control标注资源的有效期。在有效期内重复请求,浏览器不会向服务器发起请求,而是读取上一次请求的响应。

强制缓存由浏览器判断。缓存触发时,,在浏览器调试界面查看此请求,状态是“Status Code: 200 OK (from memory cache)”,表示从内存读取缓存,或“Status Code: 200 OK (from disk cache)”,表示从硬盘读取缓存。


Expires

缓存到期的日期/时间,有效格式为:“Expires: Wed, 29 May 2019 06:00:00 GMT”。

以客户端时间为准,在这个时间之后,缓存过期,需要重新发起请求。不符合格式的日期、过去的日期,同样意味着已经过期。


Cache-Control

控制该请求是否应该缓存,如果缓存的话有效期是多久。可以带有以下参数:


举个例子,对于静态图片,通常希望代理服务器和客户端都缓存较长时间,可以设置为:“Cache-Control:public, max-age=31536000”。


如上图所示,当Cache-Control和Expires字段同时存在时,Cache-Control的优先级更高。Expires是一个时间戳,如果服务器和客户端的时间不一致,可能会有误差,因此只能做粗略的控制。而Cache-Control使用相对于请求的有效时长,还可以进行更复杂的缓存设置。


协商缓存

当强制缓存未命中时,浏览器无法判断缓存是否已经过期,需要重新发起请求。服务器根据请求header里的If-Modify-Since和If-None-Match等字段判断资源是否有更新。如果有更新,直接返回更新后的结果;如果没更新,返回一个body为空的304响应:“Status Code: 304 Not Modified”,表示可以直接使用缓存。


Last-Modified

每一次http返回时,服务端在header中标明此资源最后更新的时间,格式为“Last-Modified: Wed, 1 May 2019 06:00:00 GMT”。当下次请求相同资源,并且强制缓存已过期,浏览器会自动在请求header带上这个时间,Get和Head请求使用“If-Modified-Since”字段,其他请求使用“If-Unmodified-Since”字段。服务端根据这个时间,判断返回内容从那时起是否有修改,来决定返回200还是304。


ETag

每一次http返回时,服务端在header中标明此资源的版本标识符,格式为“ETag: "<etag_value>"”。当下次请求相同资源,并且强制缓存已过期,浏览器会自动在请求header带上这个标识符,使用“If-None-Match”或“If-Match”字段。服务端根据标识符,判断返回内容和客户端缓存是否一致,来决定返回200还是304。

没有明确指定生成ETag值的方法,服务端可以自己制定规则,自己判断。可以在值前面添加'W/',表示使用弱验证器


如上图所示,当Last-Modified和Etag字段同时存在时,Etag的优先级更高。


清除缓存

缓存是个好东西,但有时候我们又需要禁用它。以下提供几种不修改接口就能禁用缓存的方法。

<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">

在运维部署时候,尤其是版本更替的时候,可能会遇到更复杂的情况。以前写过一篇《前端资源缓存与版本号更新》,也可以作为解决方案的参考。


总结

强制缓存可以减少了一次http请求/响应的过程。协商缓存虽然不能减少请求,但可以节省返回的内容。合理配置缓存逻辑,提高缓存命中率,可以有效优化加载速度。




参考文献

  1. https://tools.ietf.org/html/rfc7234

  2. https://tools.ietf.org/html/rfc5861

  3. https://tools.ietf.org/html/draft-mcmanus-immutable-00

  4. https://tools.ietf.org/html/rfc7232



本文未经许可禁止转载,如需转载请联系 JAY@oonne.com


TOP