浏览器缓存中的HTTP缓存

缓存是一把双刃剑,既能帮你,也会害你。正确地使用缓存策略,能够让用户访问网页的速度大幅提升。

cache

浏览器缓存

缓存是一种保存资源副本并在下次请求时直接使用该副本的技术。当 web 缓存发现请求的资源已经被存储,它会拦截请求,返回该资源的拷贝,而不会去源服务器重新下载。

缓存带来的优点

  • 减少网络请求延迟,提高页面访问速度
  • 降低服务器请求压力
  • 减少网络带宽的消耗,比如资源存放cdn的情况,减少带宽的使用,有效降低成本。

HTTP缓存

常见的HTTP缓存只能缓存 GET 响应,对于其他类型的响应比如 (post, put, delete) 则无能为力。

强缓存

强缓存是指通过使用Http的响应头 Expires 或 Cache-Control 对资源进行缓存有效期进行设置。两者都是通过控制资源的有效期来实现缓存策略,当对应的资源在有效期内命中,浏览器则不向后端发送通信,直接使用缓存策略命中的资源,一般浏览器会显示 from dist cache 和 from memory cache 两种。

这两者该如何去使用呢?有什么区别?

Expires

Expires是Http 1.0的产物,其实用法是后端在Http的响应头设置如下:

1
expires: Apr, 22 2019 23:58:12 GMT

其中是通过设置了一个时间戳,浏览器下次进行资源获取的时候会对比当前时间和此时间戳,如果当前时间小于该时间戳,就表示缓存仍在有效期中命中。如果要让缓存失效,则配置如下:

1
expires: -1

由以上可发现问题,Expires依赖客户端本地时间,如果客户端的本地时间错误,就会让缓存策略失效,于是Http 1.1就新增了 Cache-Control 来替代 Expires。

Cache-Control

Cache-Control 可配置的字段比较多,我们逐个来了解

no-cache: 强制确认缓存,浏览器获取资源时,浏览器都要向服务器进行通信验证缓存是否命中。

no-store: 禁止进行缓存, 强制浏览器在任何情况下都不要保留任何副本,也就是不进行任何缓存策略。

public: 公共缓存,任何路径的缓存者(CDN、代理服务器),可以无条件的缓存改资源。

private: 私有缓存,只针对单个用户或者实体(不同用户、窗口)缓存资源。

max-age=: 通过设置时间长度 max-age,表示距离请求发起的时间的秒数,判断该资源在此时间范围内以内是否命中,避免时间戳带来的问题。

s-maxage=: s-maxage 优先级高于 max-age,s-maxage 用于表示 cache 服务器上(比如 CDN)的缓存的有效时间,并只对 public 缓存有效。

可见 Cache-Control 的功能比 Expires 完善,而且优先级更高。

协商缓存

协商缓存依赖于浏览器于服务器端进行通信,浏览器需要向服务器询问当前资源是否命中缓存有效期。当请求讯问的资源命中缓存,则服务器会返回Http响应码304务端告知浏览器缓存资源命中,请求会被重定向到浏览器缓存。

Last-Modified

服务器在首次返回资源的响应中通过设置响应头 Last-Modified 当前的时间戳

1
Last-Modified: Apr, 22 2019 23:58:12 GMT

浏览器下次重新获取资源时与服务器进行通信进行协商缓存命中确认,会带上请求头 If-Modified-Since

1
If-Modified-Since: Apr, 22 2019 23:58:12 GMT

服务器接收到 If-Modified-Since 的时间戳后,比对次时间戳和资源在服务器上的最后修改时间是否一致,从而判断资源是否发生了变化。如果发生了变化,就会返回一个完整的响应内容,并在 Response Headers 中添加新的 Last-Modified 值;否则,则命中缓存,返回 304 响应,并且响应头不会再添加 Last-Modified 字段。

Last-Modified 存在一定的弊端,一个是,当编辑后的资源内容没有改变,但服务器端会认为资源被更新,因为其判断是根据文件最后编辑时间。另一个是,当修改文件速度很快,而 If-Modified-Since 的时间戳和与最后修改时间的差距无法被计算出来,所以会认为资源没有进行更新。

Etag

服务器首次返回资源设置响应头 ETag

1
ETag: W/"2123-420d462f951"

浏览器下次重新获取资源时与服务器进行通信进行协商缓存命中确认,会带上请求头 If-None-Match

1
If-None-Match: W/"2123-420d462f951"

服务器接收到 If-None-Match 的资源标识后,比对当前服务器资源的标识和 If-None-Match 的资源标识是否一样,从而判断资源是否发生了变化。如果发生了变化,就会返回一个完整的响应内容,并在 Response Headers 中添加新的 ETag 值;否则,则命中缓存,返回 304 响应,并且响应头不会再添加 ETag 字段。

Etag通过对资源进行内容的HASH计算,生成资源的标识。这样可以有效的避免 Last-Modified 的弊端,但 Etag 依赖于服务器端进行计算,会影响服务器性能。

最后用一张图标总结所有:

cache-process