讲讲 浏览器的缓存机制

浏览器缓存的核心目的就是:让浏览器少发请求、少下载资源,也就等同于让页面更快、服务器压力更小。

一、整体缓存的流程

浏览器请求一个静态资源,如:CSS、JS、图片时,顺序判断:

  1. 先查强缓存
    • 有效->直接使用本地缓存,不发请求(最快)
    • 无效->进入下一步
  2. 再查协商缓存
    • 发请求问服务器:资源变了吗?
    • 没变->返回304,直接用本地缓存
    • 变了->返回200+新资源
  3. 如果都不生效->全新请求 200+新资源

二、重点:为什么HTML 不缓存?

HTML 永远不做缓存,每次请求都必须重新请求。 原因是:

  • HTML 是"入口文件",里面引入了CSS、JS、图片
  • 如果HTML 被缓存了,你更新了页面,用户永远也看不懂你更新的新版页面
  • 浏览器每次必须拿到最新的HTML,才知道里面的资源要不要更新

这是前端工程化的基础规则。

三、强缓存

定义:浏览器直接从本地拿资源,完全不发请求到服务器。

表现:速度极快,网络面板显示 disk cache 或 memory cache。

强缓存靠两个响应头控制

第一种:Expires(HTTP 1.0,老式、不推荐)

  • 格式:绝对时间(格林威治时间)

  • 例子:

    复制代码
    Expires: Wed, 31 Dec 2026 23:59:59 GMT
  • 意思:在这个时间点之前,都用缓存

致命缺点:依赖客户端本地时间。如果用户电脑乱了、时区错误,缓存直接永远失效或者永远不会过期。

第二种:Cache-Control(HTTP 1.1,现代标准、必用)

用相对时间,不依赖客户端时间,最稳定。

最常用:

复制代码
Cache-Control: max-age=86400

意思:资源缓存 86400 秒 = 1 天

其他常用值:

  • no-cache:跳过强缓存,直接走协商缓存
  • no-store:完全不缓存(敏感数据用)
  • public:所有地方都可缓存
  • private:只有浏览器能缓存

重点问题:资源提前更新了,缓存没到期怎么办?

比如:你改了 CSS,但用户浏览器缓存还有 10 天才过期。

解决方案:文件名加哈希 / 版本号
复制代码
index.css?v=123
或者
index.abc123.css
原理
  1. HTML 每次都重新请求
  2. 新版 HTML 里引用的是新地址的 CSS
  3. 浏览器发现 URL 不一样 → 当作全新资源
  4. 直接放弃旧缓存,下载新文件

这就是前端打包工具(Webpack/Vite)自动给静态资源文件加哈希的原因。

四、协商缓存

定义:强缓存过期后,浏览器必须发请求询问服务器缓存资源是否还能用。

协商缓存两套机制

第一种:Last-Modified / If-Modified-Since(HTTP 1.0)

工作流程:

  1. 第一次请求:服务器返回最后修改时间

    复制代码
    Last-Modified: Tue, 01 Jan 2025 12:00:00 GMT
  2. 强缓存过期后,浏览器发请求带上上次服务器返回的最后修改时间:

    复制代码
    If-Modified-Since: Tue, 01 Jan 2025 12:00:00 GMT
  3. 服务器对比时间:

    • 一致 → 304 不是拿缓存,是允许使用缓存 304响应体几乎没有内容
    • 不一致 → 200 + 新资源
缺点
  • 只看时间,不看内容
  • 秒级修改可能识别不到
  • 服务器时间不同步会出问题

ETag / If-None-Match(HTTP 1.1,更精准)

基于文件内容生成唯一指纹(hash) ,比时间更可靠。

工作流程:

  1. 第一次请求:服务器返回

    复制代码
    ETag: "abc123xyz"
  2. 再次请求(强缓存过期):

    复制代码
    If-None-Match: "abc123xyz"
  3. 服务器对比 hash:

    • 一样 → 304
    • 不一样 → 200 + 新资源
优点
  • 优先级高于 Last-Modified
  • 内容变才会变,时间乱改不影响
  • 精准度 100%
缺点
  • 服务器要计算 hash,轻微增加性能消耗

五、完整的缓存工作流

复制代码
浏览器请求资源
  ↓
检查强缓存(Cache-Control / Expires)
  ↓
有效?→ 直接用本地缓存(不发请求)
  ↓
无效?→ 发请求走协商缓存
  ↓
服务器对比 ETag / Last-Modified
  ↓
未修改 → 304,用本地缓存
  ↓
已修改 → 200,返回新资源

六、我们实际开发中怎么配置?

1. HTML

不设置强缓存,每次都重新请求

2. CSS / JS / 图片

  • 加 hash 指纹

  • 设置 长强缓存(一年)

    复制代码
    Cache-Control: max-age=31536000

3. 经常变的小文件

用协商缓存:

复制代码
Cache-Control: no-cache
// noe-cache 跳过强缓存,直接走协商缓存

小结

强缓存不发请求最快,协商缓存发请求校验;HTML 永远不缓存,静态资源加指纹永不过期,更新全靠 HTML 牵引。

相关推荐
西索斯coding3 分钟前
Claude Code 工具调用返回空怎么办?claude-opus-5.5 的 input_schema 校验踩坑记录与修复方案
服务器·前端·javascript·ai
疯狂敲代码的老刘4 分钟前
MarvellousSuspender浏览器扩展:1.4K星开源标签页冻结神器,Chrome吃内存终结者的干净复活版
前端·chrome
码上上班5 分钟前
shell 脚本知识点总结
前端·chrome
程序员Sunday6 分钟前
Flex 和 Grid 有什么区别?一维布局、二维布局怎么选?
前端·css·面试
Jlzn88889 分钟前
华南PACK线自动化率怎么统计才靠谱
前端·javascript·自动化
拖孩29 分钟前
AI 时代,个人开发者到底能不能靠一个小程序赚到钱
前端·后端·微信小程序
无忧.芙桃29 分钟前
图的精髓:邻接矩阵与遍历全解析
c++·算法·面试·深度优先·广度优先
Hilaku30 分钟前
ERP选型时不问MCP,等于默认三年后再付一次集成费!
前端·javascript·程序员
程序人生88831 分钟前
几百张固定位置扫描件如何离线批量清?DocConverter Web 批量去水印链路
前端
deli00732 分钟前
一个汉字三种编码:UTF-8、GBK、UTF-16 逐字节对比实测
前端