什么是双键缓存?我们必须了解的浏览器缓存新规则!

系统 浏览器
昨天有位同学问我:“Sunday 老师,为什么我的静态资源明明缓存了,但换个站点访问,又得重新下载?” 这个本质上就是因为 双键缓存(Double-keyed Caching) 导致的。所以,咱们今天就来聊聊 双键缓存是什么,它是如何工作的,以及我们应该如何优化?

Hello,大家好,我是 Sunday。

昨天有位同学问我:“Sunday 老师,为什么我的静态资源明明缓存了,但换个站点访问,又得重新下载?”

这个本质上就是因为 双键缓存(Double-keyed Caching) 导致的。

所以,咱们今天就来聊聊 双键缓存是什么,它是如何工作的,以及我们应该如何优化?

什么是双键缓存?

在 传统的浏览器缓存 中,资源的缓存通常是 基于 URL 进行存储的。

比如,当我们访问 https://cdn.sunday.com/script.js 时,那么浏览器会缓存这个 script.js,当其他站点也引用这个 URL 时,浏览器直接复用缓存,不需要重新下载。


这种传统的缓存方式,就是开始同学所说的:资源一旦缓存,任何站点都可以访问

但这样做有一个巨大的安全隐患——跨站点追踪(Cross-site Tracking) 和 数据泄露风险。

例如:

  • 某些网站可以通过检查公共 CDN 资源的缓存状态,来推测用户是否访问过某些网站(比如:广告追踪)。
  • 黑客可以利用缓存投毒(Cache Poisoning)攻击,让用户加载被污染的资源。

为了避免这些安全问题,很多浏览器(比如:Chrome、Firefox)引入了双键缓存机制。

双键缓存的核心规则是:缓存资源时,不仅考虑 URL,还要考虑 资源是在哪个站点加载的(Origin),也就是 “站点 + URL” 作为缓存的唯一标识。

换句话说:

  • 以前 A 站 缓存的资源,B 站 可以直接复用 ✅
  • 现在 A 站 缓存的资源,B 站 需要重新下载 ❌

双键缓存是如何工作的?


双键缓存 = 站点(Origin)+ 资源 URL

让我们用一个例子来理解:

假设你访问了 网页 A 和 网页 A,它们都使用相同的 CDN 资源 https://cdn.sunday.com/script.js:

  • 传统缓存(单键缓存)

你在 网页 A 加载 script.js,浏览器缓存该文件。

你访问 网页 B,浏览器发现它请求相同的 script.js,于是直接从缓存中加载 (减少了网络请求,提高了加载速度)。

  • 双键缓存
  • 你在 网页 A 加载 script.js,浏览器缓存它,并标记为 “仅供 网页 A 使用”。
  • 你访问 网页 B,即使请求相同的 script.js,浏览器也会认为它是 一个全新的资源,需要重新下载。

不同的站点,即使请求相同的资源,仍然需要分别缓存!

这种方式提升了安全性,但是也会带来最初那位同学的疑惑,就是:资源无法跨站点共享,必须要重复下载了。

所以说:双键缓存虽然带来的“一定的”安全性,但是也带来了不少的问题,比如:

  • 缓存复用率降低:即使是相同的资源,不同站点仍然需要重新下载
  • 公共 CDN 失去部分优势:以往我们使用 CDN(如 jsDelivr、UNPKG)是为了让多个站点共用缓存,现在效果大大降低。
  • 首次访问成本上升:用户访问某个站点时,即使本地已经缓存了相同的资源,仍然需要重新下载,导致页面首次加载变慢。

如何优化双键缓存影响?

在上面,咱们已经大致了解了双键缓存的原理以及可能会带来的一些影响了,所以最后咱们就来看看如何尽可能的优化这些问题:

1. 利用 Service Worker

Service Worker 可以在客户端拦截请求,并利用 本地缓存 来减少对网络请求的依赖。

例如,我们可以使用 Cache API 将某些资源手动缓存下来,而不受双键缓存的限制:

self.addEventListener("fetch", (event) => {
  event.respondWith(
    caches.match(event.request).then((response) => {
      return response || fetch(event.request);
    })
  );
});

Service Worker 的缓存存储 不受双键缓存的影响,因此对于高频使用的静态资源,可以考虑让 Service Worker 进行管理,而不是完全依赖 HTTP 缓存。

2. 使用 HTTP/3,减少重复请求开销

由于双键缓存的影响,即使同一个用户访问不同网站,公共 CDN 资源也可能 多次下载。

但是,如果通过 HTTP/3(QUIC)协议 通过 多路复用 和 0-RTT 连接,可以优化对应的性能问题。


PS:如何检查你的 CDN 是否支持 HTTP/3?

可以在 Chrome DevTools 的 Network 面板中,查看 Protocol 列,如果显示 h3,说明该资源使用了 HTTP/3 进行传输。

3. 预加载关键资源

既然不能完全依赖浏览器缓存,我们可以主动 预加载关键资源。

例如,使用 <link rel="preload"> 来预加载字体、脚本或 CSS:

<link rel="preload" href="https://你的 cdn 地址/fonts/Roboto.woff2" as="font" type="font/woff2" crossorigin="anonymous">

这样可以确保关键资源即使因为双键缓存机制需要重新下载,也能更快地完成加载。

责任编辑:武晓燕 来源: 程序员Sunday
相关推荐

2017-09-28 12:03:40

前端

2020-03-11 20:42:34

浏览器缓存机制

2018-08-07 10:44:50

缓存技术浏览器

2017-04-26 14:15:35

浏览器缓存机制

2019-01-03 13:09:58

浏览器缓存原理

2019-02-21 10:51:37

程序员技能沟通

2017-05-15 13:40:20

浏览器http缓存机制

2020-10-29 11:04:28

缓存浏览器LocalStorag

2021-06-01 09:12:47

前端浏览器缓存

2020-07-16 08:04:21

浏览器缓存策略

2011-05-06 09:36:16

动态页面

2021-08-02 13:05:49

浏览器HTTP前端

2019-08-16 10:54:03

本地存储javascripthttp缓存

2021-07-22 09:55:28

浏览器前端缓存

2020-12-29 09:56:29

浏览器缓存HTTP

2018-11-30 09:00:19

html5cssjavascript

2016-01-05 12:54:52

浏览器浏览器端缓存

2018-04-28 10:54:31

缓存服务器运作

2022-03-24 08:31:25

Web性能优化浏览器缓存API封装

2009-03-23 08:52:51

点赞
收藏

51CTO技术栈公众号