HTTP 缓存的历史

缓存的优点

  1. 减少了传输数据的冗余
  2. 减少了带宽的占用
  3. 减少了服务器的开销
  4. 降低了时延,增加了用户效率

缓存方式

主要包括,浏览器缓存、代理服务器缓存,http协议中的强缓存和协商缓存。

浏览器缓存与HTTP缓存

缓存命中

缓存命中与否分为三种情况

  1. 缓存命中 cache hit - 200(memory cache, disk cache)
  2. 缓存未命中 cache miss - 200
  3. 缓存再验证 cache revalidation
    再验证缓存命中 revalidation hit - 304
    再验证缓存未命中 revalidation miss - 200

浏览器缓存

内存缓存:
当浏览器加载一个页面时,它会将页面中的静态资源(例如脚本、样式、图片等)缓存到内存中。这些资源可以快速加载,因为它们在内存中的访问速度比在硬盘中的快得多。内存缓存的原理是将资源加载到浏览器内存中,并在后续请求该资源时,直接从内存中读取,不再向服务器发送请求。
磁盘缓存:
当浏览器第一次加载一个页面时,它会将页面中的静态资源(例如脚本、样式、图片等)缓存到磁盘中。这些资源可以在后续访问时快速加载,因为它们已经被缓存在磁盘中。磁盘缓存的原理是将资源写入到硬盘中,并在后续请求该资源时,先从硬盘中读取,如果存在,则不再向服务器发送请求,而是直接返回缓存的数据。
二者的一个显著特点是,内存缓存的数据会随着浏览器的关闭而失效,而磁盘缓存的数据会一直保留,直到过期或者手动清除。

强缓存

  1. Cache-Control: max-age=xxx(s) and Expires (HTTP/1.0)
    max-age 可以设置一个相对时间,而Expires 只能设置一个j绝对时间,如果同时存在,max-age 优先级高于 Expires.
    使用场景是:
    当设置 cache-control: max-age=3600时,在1个小时内,浏览器都会直接从缓存中读取资源,而不会向服务器发送请求。当超过一个小时时,浏览器才会向服务器发送请求,获取最新的资源。
    当设置 Expires: Wed, 21 Oct 2020 07:28:00 GMT 时,在2020年10月21日07:28:00之前,浏览器都会直接从缓存中读取资源,而不会向服务器发送请求。当超过这个时间时,浏览器才会向服务器发送请求,获取最新的资源。

相对来说maxage 会比expires 来的更加灵活
当资源的有效期比较短,例如一些动态资源,可以使用 max-age,当资源的有效期比较长,例如一些静态资源,可以使用 Expires。

协商缓存

服务器再验证缓存过期.
场景是:
cache-control and expires 过期时,这时不代表缓存是不能用了。而是需要向服务器发送请求,验证缓存是否可用。

  1. 如果验证的内容发生了变化,那么服务器会返回最新的资源,更新缓存服务器,且返回到客户端;
  2. 如果验证的内容没有发生改变,那么服务器会返回304,告诉客户端直接使用缓存。
    使用协商缓存,通过条件缓存字段实现。

条件缓存字段

If-Modified-Since/Last-Modified and IF-None-Match/Etag

客户端通常在收到来自服务器的HTTP响应时,缓存 ETag 和 Last-Modified 头部。这些首部包含了有关服务器上资源版本信息。客户端可以用他们判断缓存的资源是否过期。

当客户端发出GET 请求并收到带有ETag 和 Last-Modified 响应头的HTTP响应时,会把这些信息缓存起来。当第二次请求相同的资源时,客户端会把这些信息放在请求头中发送给服务器。服务器会比较客户端请求头中的 ETag 和 Last-Modified 与服务器上资源的 ETag 和 Last-Modified 是否匹配。如果匹配,服务器会返回一个空的响应体,告诉客户端可以使用缓存的资源。如果不匹配,服务器会返回最新的资源,且返回到客户端。
If-Modified-Since 作为请求头的一部分,存放的是Last-Modified的缓存。当发送到服务器时,服务器回去对比If-Modified-Since和当前服务器上的实际文件的Last-Modified 是否一致,如果一致,说明文件没有修改过,直接返回304,客户端继续使用缓存文件;如果不一致,说明文件有修改,那么返回200,同时返回最新的文件内容。
同理,If-None-Match 相同的道理,只是If-None-Match 存放的是Etag的缓存。当发送到服务器时,服务器回去比对If-None-Match 和当前服务器上实际该文件的ETag 是否一致,如果一致,说明文件没有修改过,直接返回304,客户端继续使用缓存文件;如果不一致,说明文件有修改,那么返回200,同时返回最新的文件内容。

权重

source: bing.com/chat
当 If-None-Match 和 If-Modified-Since 请求头同时出现在一个 HTTP 请求中时,服务器会忽略 If-Modified-Since 请求头。这是因为 If-None-Match 请求头被认为是 If-Modified-Since 请求头的更精确替代品,两者仅为了与可能不实现 If-None-Match 的旧中间件进行互操作而组合在一起。
因此,当服务器支持 If-None-Match 时,它的优先级高于 If-Modified-Since

Q&A

  1. 如何操作使得浏览器未命中内存缓存
    打开一个新的私密窗口:使用浏览器的私密模式,可以避免使用内存缓存,因为私密模式通常不会将任何数据缓存在内存中。

    禁用缓存功能:在浏览器开发者工具中,可以勾选禁用缓存选项,这样每次刷新页面都会从服务器重新获取资源,而不会使用内存缓存。

    强制刷新页面:在浏览器中按下 Ctrl+F5(Windows)或 Cmd+Shift+R(Mac)键,可以强制浏览器忽略本地缓存和代理缓存,重新请求页面资源。

    修改请求头:在每次请求资源时,可以通过修改请求头信息,告诉服务器不要返回缓存数据。例如,在请求头中加入 “Cache-Control: no-cache” 或 “Pragma: no-cache” 等字段,就可以避免使用内存缓存。

附录

cache-control 有哪些字段