讲讲 浏览器的缓存机制

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

一、整体缓存的流程

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

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

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

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

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

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

三、强缓存

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

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

强缓存靠两个响应头控制

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

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

  • 例子:

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

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

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

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

最常用:

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

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

其他常用值:

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

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

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

解决方案:文件名加哈希 / 版本号
diff 复制代码
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. 第一次请求:服务器返回最后修改时间

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

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

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

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

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

工作流程:

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

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

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

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

五、完整的缓存工作流

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

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

1. HTML

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

2. CSS / JS / 图片

  • hash 指纹

  • 设置 长强缓存(一年)

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

3. 经常变的小文件

用协商缓存:

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

小结

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

相关推荐
掘金者阿豪3 小时前
把业务数据变成共享仪表盘:Metabase可视化与远程访问实践
前端·后端
kyriewen3 小时前
折腾了半年 AI 编程工作流,最后发现效率瓶颈是桌上那块屏幕
前端·javascript·ai编程
蜗牛前端4 小时前
codex 全流程开发上线的高颜值礼簿小程序
前端·微信小程序
大龄秃头程序员4 小时前
我在图文流 App 里落地双层缓存、弱网降级与 OOM 治理
前端
老王以为4 小时前
React Renderer 分离的多平台架构
前端·react native·react.js
hunterandroid5 小时前
Kotlin Coroutines 与 Flow:让异步任务更清晰
前端
Bigger5 小时前
从零搭建 AI 代码审查服务:一份前端也能看懂的 Python 学习笔记
前端·ci/cd·ai编程
lichenyang4535 小时前
JSAPI、NAPI、Biz、Imp:ASCF Demo 如何真正调用系统能力和 C++ 能力
前端
自由路飞6 小时前
RAG 混合检索深挖:BM25 和向量分数为什么不能直接相加?
面试
lichenyang4536 小时前
IPC、JSVM、UIThread、libuv:ASCF 架构图里最容易混的几个词
前端