前言
HTTP 属于客户缓存,我们常认为浏览器有一个缓存数据库,用来保留一些静态文件
当缓存数据库中有客户端需要的数据,如果数据未失效,客户端直接将数据拿出来使用。当缓存没有需要的数据时,客户端才会向服务端请求。
通常浏览器的缓存策略分为两种:强缓存和协商缓存
强制缓存
- 对于强制缓存,服务器响应的 header 中会用
Expires 和 Cache-Control - 强缓存表示在缓存期间
不需要请求,code 值为200
Expires
Expires: Wed, 22 Oct 2018 08:41:00 GMT
- Expires 的值为服务器返回数据的到期时间;如果再次请求的时间小于此时间,则直接使用缓存数据。 缺点:
Expires 受限于本地时间,如果修改了本地时间,可能会造成缓存失效。- 服务器时间和客户端时间可能有误差,也将导致缓存命中误差。
Cache-Control
Cache-Control: max-age=30
Cache-Control优先级高于 Expires。如上表示该资源在30秒后过期,需再次请求。
- Cache-Control 有很多属性,不同属性代表不同意义。
- private:客户端可以缓存
- public:客户端、代理服务器都可以缓存
- max-age=t:缓存内容将在 t 秒后失效
- no-cache:需要使用协商缓存来验证缓存数据
- no-store:所以内容都不缓存
现在一般使用 Cache-Control
协商缓存
又称对比缓存。客户会先从缓存数据库拿到一个缓存的标识,然后向服务端验证标识是否失效,如果没有失效 服务端会返回304,这样客户端可以直接去缓存数据库拿出数据,如果失效,服务端会返回新的数据。
对于协商缓存一共有两种方案:Last-Modified,Etag
Last-Modified
Last-Modified:服务器告诉浏览器资源的最后修改时间
浏览器再次请求服务器时,请求头会包含字段,后面跟缓存中获得的最后修改时间
is-Modified-Since字段- 从某个时间节点算起,是否文件被修改了。
- 服务器收到后与请求资源最后修改时间进行对比,如果一致则返回 304
- 不一致则响应整个资源
is-Unmodified-since字段- 从某个时间节点算起,是否文件没有修改
- 如果没有被修改:则开始传送文件;
- 如果被修改则不传输,并返回 412 (预处理错误)
两者的区别是一个修改了才下载,一个是没修改才下载
缺点:
- 服务器上的资源可能被修改,而实际内容根本没发生改变,但是会因为 Last-Modified 时间匹配不上而返回给客户端。
Last-Modified只能以秒计时,如果在不可感知的时间内完成文件修改(一秒内),服务器还是会认为资源命中了,不会返回正确的资源。
Etag
服务器响应请求时,通过此字段告诉浏览器当前资源在服务器生成的唯一标识(生成规则由服务器决定)
if-None-Match字段:再次请求时,浏览器从缓存中获取标识,在请求头中包含此字段,服务器收到后做对比。- 相同则返回 304
- 不同则说明资源有改动,则响应整个资源内容
ETag 优先级高于 Last-Modified- ETag 类似于文件指纹
缺点:
- 但标识是通过计算出来的,会占用服务端计算的资源。
一般来说,现在会使用工具来打包代码,可以对文件名进行哈希处理,只有当代码修改后才会生成新的文件名。这样就可以当文件名修改时才去下载最新的代码文件
执行过程
- 浏览器地址栏写入 URL,回车后如果发现缓存中有这个文件,则不请求直接在缓存中拿数据。
- F5:浏览器发送请求并带上
if-modify-since,服务器检查这个文件是否过期 - Ctrl + F5:将缓存中该文件删除,重新请求完整资源。
其他
强制缓存的优先级高于协商缓存,若两种缓存都存在,且强制缓存命中目标,则协商缓存不在验证标识
缓存的优点
- 减少冗余的数据传递,节省宽带流量
- 减少服务器负担,大大提高网站性能
- 加快了客户端加载网页的速度(这也是 HTTP 缓存属于客户端缓存的原因)