浏览器缓存方案

205 阅读3分钟

一、浏览器缓存的核心作用与分类

作用:减少网络请求,提升页面加载速度,降低服务器压力。
分类

  1. 强缓存:浏览器直接从本地缓存获取资源,不发请求到服务器;
  2. 协商缓存:发送请求到服务器验证缓存是否有效,有效则返回304状态码,浏览器使用本地缓存。

二、强缓存实现方案(Cache-Control/Expires)

1. Cache-Control(HTTP/1.1,推荐)
  • 核心指令
    Cache-Control: max-age=31536000  // 缓存1年(单位:秒)
    Cache-Control: no-cache         // 强制协商缓存
    Cache-Control: no-store         // 禁止缓存
    Cache-Control: public/private   // 缓存可见范围
    
  • 示例配置(Nginx)
    location ~* \.(js|css|png|jpg|jpeg|gif|svg)$ {
      expires 1y;  // 等价于Cache-Control: max-age=31536000
      add_header Cache-Control "public";
    }
    
2. Expires(HTTP/1.0,兼容性好)
  • 格式
    Expires: Thu, 01 Jan 2024 00:00:00 GMT  // 绝对过期时间
    
  • 与Cache-Control的优先级
    • 若同时存在,Cache-Control 优先级更高(因 Expires 依赖服务器时间)。

三、协商缓存实现方案(Last-Modified/ETag)

1. ETag(推荐,更精准)
  • 原理:服务器为资源生成唯一标识(如文件哈希值),浏览器请求时通过 If-None-Match 发送标识,服务器对比后返回304(未修改)或200(修改)。
  • 示例流程
    1. 首次请求:服务器返回资源+ETag: "abc123"
    2. 再次请求:浏览器发送 If-None-Match: "abc123"
    3. 服务器对比标识,未修改则返回304,否则返回新资源。
2. Last-Modified/If-Modified-Since
  • 原理:服务器返回资源最后修改时间(Last-Modified),浏览器下次请求时通过 If-Modified-Since 发送时间,服务器对比后判断是否更新。
  • 缺点
    • 精度有限(仅精确到秒);
    • 无法检测文件内容未变但修改时间变更的情况(如编辑器自动保存)。

四、缓存策略对比表

策略强缓存协商缓存
核心字段Cache-Control/ExpiresETag/Last-Modified
是否发请求否(直接读本地)是(验证缓存有效性)
服务器压力中(需验证请求)
更新及时性差(需等max-age过期)好(每次请求验证)

五、各类资源的缓存策略

1. 静态资源(JS/CSS/图片)
  • 策略
    • 强缓存(max-age=31536000)+ 版本号(如 app.v1.0.0.js);
    • 版本更新时修改文件名,强制浏览器加载新资源。
  • Nginx配置
    location ~* \.(js|css|png|jpg|jpeg|gif|svg|woff|woff2|ttf|eot)$ {
      expires 1y;
      add_header Cache-Control "public, max-age=31536000";
      add_header ETag on;  // 开启ETag协商缓存
    }
    
2. HTML页面
  • 策略
    • 不缓存或短缓存(max-age=0)+ 协商缓存(ETag);
    • 因HTML常包含动态内容,避免强缓存导致页面不更新。
  • 配置
    location / {
      expires 0;
      add_header Cache-Control "no-cache, no-store, must-revalidate";
      add_header Pragma "no-cache";
    }
    
3. 动态接口(API)
  • 策略
    • 禁止缓存(Cache-Control: no-cache);
    • 或根据业务需求设置短缓存(如5分钟)。

六、问题

1. 问:强缓存和协商缓存的执行顺序?
    1. 浏览器先检查强缓存(Cache-Control/Expires),有效则直接使用本地缓存;
    2. 强缓存失效后,发送请求到服务器验证协商缓存(ETag/Last-Modified),有效则返回304;
    3. 协商缓存失效后,服务器返回新资源(200 OK)。
2. 问:如何强制浏览器更新缓存?
    • 前端:修改资源URL(如加版本号 ?v=2.0);
    • 后端
      1. 发送 Cache-Control: no-cache 强制协商缓存;
      2. 更改 ETagLast-Modified 值,使协商缓存失效。
3. 问:ETag和Last-Modified的优缺点?
    • ETag
      ✅ 优点:精准检测资源变化(基于内容哈希);
      ❌ 缺点:计算哈希有性能开销,资源量大时影响服务器效率。
    • Last-Modified
      ✅ 优点:实现简单,服务器压力小;
      ❌ 缺点:精度低,无法检测内容未变但修改时间变更的情况。
4. 问:如何处理缓存导致的登录状态失效?
    • 在响应头中添加 Cache-Control: private(仅客户端可缓存);
    • 或对包含登录状态的资源设置 Cache-Control: no-cache,强制每次请求验证;
    • 前端路由跳转时,通过 window.location.reload(true) 强制刷新(跳过强缓存)。

七、缓存调试与优化工具

  1. Chrome DevTools

    • Network面板:查看请求的缓存状态(from disk cache/from memory cache/304 Not Modified);
    • 禁用缓存:勾选 Disable cache 可临时关闭缓存,方便开发调试。
  2. Lighthouse

    • 审计缓存策略是否合理,给出优化建议(如“可缓存的资源未设置缓存”)。
  3. 服务器日志

    • 分析 304 请求比例,评估缓存命中率(理想情况下静态资源命中率应>80%)。