当前位置: 首页 > article >正文

请谈谈 HTTP 中的缓存控制,如何使用 Cache-Control 和 ETag 进行缓存管理?

一、缓存控制的核心逻辑(用说人话的方式)

想象你每天早上去便利店买牛奶。缓存机制就像老板问你:"还是拿和昨天一样的盒装鲜奶吗?" 如果牛奶没过期(缓存有效),直接拿走不用付钱(不请求服务器);如果过期了(缓存失效),老板才会去仓库拿新的(重新请求)。

关键角色

  • Cache-Control:便利店老板的备忘录,写着"鲜奶保质期3天"
  • ETag:牛奶盒上的唯一编号,用来确认是不是同一批货
  • Last-Modified:牛奶的生产日期

二、缓存工作流程(配真实案例)
2.1 强缓存阶段(不询问服务器)
# 首次请求响应头
Cache-Control: max-age=3600  # 1小时有效期
ETag: "abc123"

此时浏览器直接把资源存到内存(memory cache)或磁盘(disk cache),1小时内重复请求直接读取缓存,不会产生任何网络请求​(Chrome DevTools看到灰色from disk cache

2.2 协商缓存阶段(需要问服务器)

当缓存过期后,浏览器带着「身份证」问服务器:

# 二次请求头
If-None-Match: "abc123"  # 上次的ETag值

服务器对比ETag:

  • 相同 → 返回304 Not Modified(空body,省流量)
  • 不同 → 返回新资源+新ETag

三、缓存头字段详解(配代码实战)
3.1 Cache-Control常用指令
// Node.js设置响应头(Express示例)
app.get('/static/logo.png', (req, res) => {
  // 强缓存1年(适用于带hash的静态资源)
  res.set('Cache-Control', 'public, max-age=31536000, immutable')
  
  // 禁止缓存(敏感数据)
  // res.set('Cache-Control', 'no-store')
  
  // 缓存但每次验证(适合频繁更新的API)
  // res.set('Cache-Control', 'no-cache')
})

指令对比表

指令效果适用场景
max-age=3600缓存有效期3600秒静态资源
no-cache缓存但每次必须验证需要实时性的数据
no-store禁止存储任何缓存敏感数据(如支付接口)
immutable即使过期也直接使用带hash的静态文件
3.2 ETag生成策略
// 用文件内容生成ETag(避免时间戳导致的误判)
const crypto = require('crypto')
const fileContent = fs.readFileSync('data.json')
const etag = crypto.createHash('md5').update(fileContent).digest('hex')

app.get('/api/data', (req, res) => {
  res.set('ETag', etag)
  
  // 处理协商缓存
  if (req.headers['if-none-match'] === etag) {
    return res.status(304).end()
  }
  
  res.json({ data: 'new content' })
})

四、开发中的缓存管理技巧(避坑指南)
4.1 静态资源最佳实践
<!-- 带hash的文件名实现永久缓存 -->
<script src="/js/app.3a87b6.js"></script>

<!-- 后端配置 -->
app.use(express.static('public', {
  maxAge: '1y',
  immutable: true  // 关键!告诉浏览器不用验证
}))
4.2 动态接口防缓存污染
// 强制跳过浏览器缓存(调试用)
fetch('/api/user', {
  headers: {
    'Cache-Control': 'no-cache',  // 添加该头让浏览器强制验证
    'Pragma': 'no-cache'          // 兼容旧浏览器
  }
})
4.3 CDN缓存联动
# 源服务器响应头
Cache-Control: public, max-age=600      # 告诉CDN缓存10分钟
CDN-Cache-Control: public, max-age=3600 # CDN覆盖设置(部分厂商支持)

五、实际踩坑案例分析
5.1 版本号失效问题
<!-- 错误示范:用时间戳导致缓存失效 -->
<link href="/css/style.css?v=20230815">

<!-- 正确做法:基于文件内容生成hash -->
<link href="/css/style.a3c8f1.css">
5.2 移动端缓存异常

iOS Safari有时会无视no-store

// 添加随机参数绕过缓存
fetch(`/api/items?t=${Date.now()}`)
5.3 浏览器前进后退陷阱

某些浏览器在「前进/后退」时直接使用内存缓存:

// 页面初始化时主动验证
window.addEventListener('pageshow', (event) => {
  if (event.persisted) { // 从缓存恢复时触发
    location.reload()
  }
})

六、缓存调试技巧(Chrome DevTools实战)
  1. Network面板过滤

    • 灰色标记(from disk cache) → 强缓存生效
    • 304状态码 → 协商缓存生效
  2. 禁用缓存调试

    • 勾选DevTools的Disable cache(等效于Cache-Control: no-store
  3. 强制刷新

    • Ctrl+Shift+R(Windows)清空缓存重新请求

总结 Checklist

  1. 静态资源Cache-Control: max-age=31536000, immutable + 带hash文件名
  2. 动态接口Cache-Control: no-cache + 合理设置ETag
  3. 敏感数据:始终使用Cache-Control: no-store
  4. 部署更新:修改文件名或添加版本号触发缓存失效
  5. 监控异常:通过日志监控304比例,优化缓存策略

缓存管理就像给网站做「物资调度」,合理使用能让加载速度提升数倍。

建议通过实际项目的瀑布流分析,观察哪些资源可以延长缓存时间,哪些需要严格控制实时性。记住:缓存不是洪水猛兽,用对了就是性能利器。


http://www.kler.cn/a/576003.html

相关文章:

  • 嵌入式仿真实验教学平台替换Proteus,嵌入式教学创新的新选择
  • Facebook 与信息传播:塑造新闻和媒体的新生态
  • 混元图生视频-腾讯混元开源的图生视频模型
  • Crawl4AI: 赋能AI用户的开源智能网页爬虫与数据提取
  • 电商项目-秒杀系统(四)秒杀异步下单防止重复秒杀
  • Firefox缩小标签页高度以及自定义调整
  • 游戏引擎学习第138天
  • 最长递增子序列题目--蓝桥oj742合唱队形(超详细版,思路清晰)
  • TMS320F28P550SJ9学习笔记6:SCI所有寄存器__结构体寄存器方式配置 SCI通信初始化__库函数发送测试
  • 04.基于C++实现多线程TCP服务器与客户端通信
  • GB28181视频监控流媒体平台LiveGBS如何自定义收流端口区间以便减少收流端口数或解决端口冲突问题
  • MySQL 数据库优化与定期数据处理策略
  • 卡尔曼滤波算法从理论到实践:在STM32中的嵌入式实现
  • 【2025年后端开发终极指南:云原生、AI融合与性能优化实战】
  • Linux学习笔记(以Ubuntu为例)
  • 洛谷B2074 计算星期几
  • 批量多线程下载ERA5数据
  • Qt的QGroupBox的使用方法
  • 【数据挖掘]Ndarray数组的创建
  • 研究案例:英伟达研究中心,华盛顿大学——TacSL:使用Franka机器人的视觉触觉传感器模拟和学习库