3 分钟带你了解协商缓存和强缓存

90 阅读3分钟

3 分钟带你了解协商缓存和强缓存

老生常谈,今天聊一聊浏览器里的缓存机制。 协商缓存(Conditional Cache)和强缓存(Strong Cache)都是 HTTP 协议中的缓存机制,用于提高网页加载速度

  • 强缓存:浏览器会根据缓存的响应头信息,判断缓存是否可用,如果可用则直接返回缓存内容,而不会向服务器请求数据
  • 协商缓存:服务端根据请求头信息,判断浏览器缓存是否可用,如果可用继续使用浏览器缓存,不可用返回最新的数据

整体流程

缓存.jpg

字段说明

Cache-Control

这个字段决定浏览器和服务端的缓存策略,是 HTTP 1.1 引入的

  • no-store: 所有内容都不会被缓存到缓存或 Internet 临时文件中, 这里分两种情况

    1. 浏览器设置了 Cache-Control: no-store,服务端未设置时,走的是协商缓存逻辑。
    graph LR
      A[请求] --> B[200] --> C[再次请求] --> D[304]
    
    1. 服务端设置了 Cache-Control: no-store,浏览器不论是否设置,都会每次请求内容
    graph LR
      A[请求] --> B[200] --> C[再次请求] --> D[200]
    
  • no-cache: 强每次请求都会向服务器请求数据,走协商缓存逻辑。和上面no-store里的第一种情况差不多

  • max-age=xxx: 指定缓存时间,超过时间后,缓存失效,下次请求会向服务器请求数据,走协商缓存逻辑。(实测下来,只有客户端设置了 max-age=0 才有用,此时客户端不会强缓存)

Pragma 和 Expires

  • Pragma 和 Expires 都是 HTTP 1.0 的缓存控制字段,为了兼容老旧的服务器,仍然可以同时使用 Pragma 和 Cache-Control
  • Pragma 的有效值为:no-cache, no-store。效果和 Cache-Control 一样
  • Expires 表示内容的过期时间。如果客户端时间不准确,有可能会导致缓存失效,重新发送请求。估引入 Cache-Control:max-age=xxx。其实用户改变客户端时间,也是不影响缓存时间

整体流程解析

前提要求:通过前面字段说明,我们知道开启浏览器缓存条件

客户端请求头,不能设置缓存失效。比如 no-store, no-cache, max-age=0

服务端设置了缓存时间。比如 Cache-Control: max-age=86400,或者 Expires: Thu, 01 Jan 1970 00:00:00 GMT

  1. 发送get请求,是否有缓存

  2. 有缓存,强缓存是否新鲜

    判断规则,通过 Cache-Control: max-age=86400 或者Expires: Thu, 01 Jan 1970 00:00:00 GMT,如果同时存在,cache-control 优先级高 image.png

  3. 如果缓存过期,发送请求询问服务端,走协商缓存

    请求头中,会携带上一次响应里面的 EtagLast-Modified。分别是 if-none-match: 【Etag】if-modified-since: 【Last-Modified】

    通过 etag 判断的准确性会高于通过修改时间

    因为【修改时间】的缓存逻辑,在以下场景会有问题

    • 服务端定时程序周期性修改文件修改时间,但是文件内容没有改变,导致缓存失效,发送请求
    • 修改时间只能精确到秒,如果修改时间间隔小于秒,就会导致缓存失效,发送请求 image-1.png

浏览器和服务端如何设置缓存策略

  1. 浏览器设置缓存策略
<html>
  <head>
    <!--或者为其他合法值 content="max-age=86400"-->
    <meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
    <meta http-equiv="Pragma" content="no-cache" />
    <meta http-equiv="Expires" content="0" />
    <!-- 其他<head>中的内容 -->
  </head>
</html>
  1. nginx 服务器设置缓存策略
http {
  // 写在这里作用于全局
  server {
    location / {
      // 添加响应头
      add_header Cache-Control "max-age=3600";
      root html/stable;
      try_files $uri $uri/ /index.html;
    }
  }
}