离线打开页面,本地字体全变成系统默认,Network 里字体请求显示来自缓存但状态是 opaque,字体文件大小显示为 0。乍看像缓存或者权限的锅,追下去往往不是。

const res = await fetch(url, {mode: 'cors'});
if (res.type === 'opaque') return;
await cache.put(url, res.clone());

追下去是这么回事:跨域请求没带 CORS 头时响应类型是 opaque,可以被缓存但读不到内容和状态码。部分浏览器在离线时直接判定这种响应不可用,等于白存。

碰到「opaque 响应缓存」这类问题,我习惯先把当前配置原样备份一份,改坏了立刻换回来,不用现场推。验证用真实数据走一遍,测试数据太干净,边界情况根本碰不到。

能分两步做的操作就别合成一步,中间看一眼返回值,出问题好判断。报错里带路径的,先去看那个路径在不在、权限对不对。

同一份配置存在多处的,先确认改的是被加载的那一份。

具体做法是,字体服务器补上 Access-Control-Allow-Origin,让响应变成 cors 类型;注册 SW 时给字体请求设置 mode: 'cors',别用 no-cors;缓存前检查 response.type,opaque 的条目直接跳过。

验收就看一点,断网重开页面,自定义字体正常显示,Network 里字体状态码是 200 而不是 opaque。

作者 9823189