浏览器缓存和 CDN 缓存到底有什么区别?

HTTP1周前发布 admin
125 0

做前端的同学基本都听过这两个词:浏览器缓存、CDN 缓存。面试也爱问,平时排查线上问题(比如”我明明发布了新版本,为什么用户还是看到旧页面”)也经常会撞上它们。

但很多人对这两者的理解停留在”反正都是缓存,能让网页加载快点”,具体谁负责什么、出了问题该查哪个,往往说不清楚。今天就把这两个概念彻底捋顺。

先说一个类比

想象你在网上买了一本书。

  • 浏览器缓存,相当于你自己家里的书架。你买过、看过的书,直接放在自己书架上,下次想看,伸手就拿,根本不用出门。
  • CDN 缓存,相当于你家小区门口新开的一家书店分店。这家分店本身不出版书,但是会从出版社(也就是源站)批发一批热门书屯在店里。你去买的时候,不用跑到几百公里外的出版社仓库,在小区门口就能买到,速度快很多。

浏览器缓存服务的是”你自己”,只帮你一个人省事;CDN 缓存服务的是”你家附近所有人”,帮一片区域的用户都省事。这就是两者最本质的区别——缓存发生的位置和服务的对象完全不同

下面展开讲。

浏览器缓存:存在你自己电脑里

浏览器缓存,顾名思义,缓存的内容就存在用户自己的设备上(硬盘或者内存里)。当你访问一个网站,浏览器会把图片、CSS、JS 这些静态资源下载下来,同时按照服务器返回的规则,把它们存一份在本地。下次你(只有你)再访问同一个页面,浏览器一看:”咦,这个资源我本地有还没过期”,直接从本地读取,连网络请求都不用发。

浏览器缓存主要靠 HTTP 响应头来控制,核心是这么几个:

  • Cache-Control:告诉浏览器这个资源能缓存多久、能不能缓存。比如 max-age=31536000 就是说”这玩意儿一年内都别再问我要新的了,你本地存的就是对的”。
  • Expires:老一点的写法,指定一个绝对过期时间,作用和 max-age类似,现在基本被 Cache-Control 取代。
  • ETag / Last-Modified:这两个是用来做”协商缓存”的。就是缓存到期之后,浏览器不敢直接用本地版本,就带着这个标记去问服务器:”我这份还是最新的吗?”如果服务器说”没变”,就返回一个 304 状态码,浏览器就继续用本地缓存,连文件内容都不用重新传,只是确认了一下”没过期”。

所以浏览器缓存其实分两种状态:强缓存(时间没到,直接用本地的,连请求都不发)和协商缓存(时间到了,但去问一下服务器有没有更新,服务器说没更新就还是用本地的)。

有个特点要注意:浏览器缓存是私有的,只属于当前这台设备、这个浏览器。你换台电脑、换个浏览器,甚至同一浏览器换个用户配置,缓存全部清零,得重新下载。这也是为什么它在 HTTP 里经常被标记为 private——这份缓存只许你自己用,不能被别人(比如你和同事共用的公司代理服务器)拿去复用。

CDN 缓存:存在离用户更近的服务器上

CDN,全称内容分发网络(Content Delivery Network)。它的缓存节点不在用户的电脑上,而是分布在全国甚至全球各地的机房里,通常离用户的物理距离比”源站”(也就是网站真正的服务器)近得多。

工作原理大概是这样:你的网站资源本来只放在一台(或几台)源站服务器上,比如在北京。如果所有用户的请求都跑到北京这台服务器去要数据,广州、成都、深圳的用户都要绕一大圈,延迟高不说,服务器压力也大。

于是就在全国各地部署很多台 CDN 节点服务器,第一次有广州用户访问时,广州节点发现自己没有这个资源,就去北京源站拉一份回来,存在自己这里,同时把内容返回给用户。后面广州地区其他用户再访问同一个资源,广州节点直接把本地存的这份发出去,根本不用再跑一趟北京,这就叫回源只发生了一次,后续都是”就近服务”。

CDN 缓存有几个和浏览器缓存很不一样的地方:

  1. 服务对象是一整片区域的所有用户,而不是单个用户。同一个 CDN 节点上的缓存,广州的张三、李四、王五访问,用的是同一份缓存副本。这在 HTTP 语义里对应的是 public 缓存——大家都能用,不区分身份。
  2. 控制权在网站运营方手里,用户完全感知不到、也无法直接操作 CDN 缓存。你没法像清浏览器缓存那样,点一下按钮去清空 CDN 上的缓存,只能通过后台管理系统发起”刷新缓存”或者”预热”的请求。
  3. CDN 除了缓存资源,往往还承担了 负载均衡、防攻击(比如抗 DDoS)、就近接入 等一堆职责,缓存只是它众多功能里的一个,但确实是最常被普通开发者接触到的一个。

两者最核心的几点区别,列个表

维度 浏览器缓存 CDN 缓存
存储位置 用户本地设备 分布在各地的 CDN 节点服务器
服务对象 单个用户(当前浏览器) 该节点覆盖区域内的所有用户
控制方 用户可以主动清除 由网站运营方通过后台控制、刷新
典型 HTTP 标识 private public
生效范围 只影响”我”这一台设备 影响整个区域甚至全国用户
更新方式 等过期,或用户手动清缓存 主动刷新/预热,或等 TTL 到期
主要目的 省掉网络请求,加快本地二次访问 缩短用户和资源之间的物理距离,分摊源站压力

请求发生时,两者到底谁先谁后

理解顺序其实很关键,能帮你排查真实问题。一个典型的资源请求流程是这样的:

  1. 浏览器先看自己本地有没有这个资源的强缓存,没过期的话直接用,请求到此结束,网络请求都不发。
  2. 如果本地缓存过期了或者没有,浏览器才真正发出网络请求。
  3. 这个请求会先打到离用户最近的 CDN 节点(而不是直接打到源站)。
  4. CDN 节点如果自己存了这份资源且没过期,直接把内容返回给用户,这个过程完全不用麻烦源站。
  5. 如果 CDN 节点上也没有或者过期了,CDN 才会去回源——找网站真正的源站服务器要最新内容,拿到之后自己存一份,再返回给用户。

所以完整链路是:浏览器缓存 → CDN 缓存 → 源站,一层一层往后兜底,只有前面这层没命中,才会麻烦到下一层。这也是为什么”就近多级缓存”能大幅减轻源站压力——绝大多数请求根本不会真正到达源站。

一个常见的排查场景

回到开头提的那个问题:”我发布了新版本,为什么用户还是看到旧页面?”

现在你应该能猜到,问题可能出在两个地方,得分开排查:

  • 如果是浏览器缓存没更新,用户强制刷新(Ctrl+Shift+R)能立刻看到新版本,因为强制刷新会跳过本地强缓存直接发请求。
  • 如果强制刷新也没用,那大概率是 CDN 缓存 还没更新——CDN 节点上存的还是旧文件,得等 CDN 缓存的有效期(TTL)到期自动更新,或者手动在 CDN 后台触发一次”缓存刷新”,让节点重新回源拉取最新内容。

实际项目里,前端工程化经常会用给静态资源文件名加哈希值的办法(比如 app.a1b2c3.js)来彻底绕开这个麻烦:文件内容一变,文件名就变,新文件名对浏览器和 CDN 来说都是”从没见过的新资源”,自然不会有旧缓存的问题,也就不用纠结到底该等谁过期了。

小结

一句话概括区别:浏览器缓存离用户最近,只服务一个人;CDN 缓存离用户较近,服务一整片区域的人。两者不是互相替代的关系,而是配合工作的两层缓存机制,共同的目标都是让用户少等一会儿、让源站少扛一点压力。搞清楚这个层级关系,日常排查缓存类问题时就能少走很多弯路。

© 版权声明

相关文章

暂无评论

none
暂无评论...