检测初始HTML文档缓存来源的JavaScript API查询
检测初始HTML文档缓存来源的JavaScript方案
问题背景
我们需要判断初始HTML文档的来源:浏览器缓存、CDN缓存还是源站。其中CDN缓存和源站可通过CDN返回的server-timing头直接区分,但如何通过JavaScript API检测文档是否直接来自浏览器缓存是核心难点,且需排除依赖开发者工具网络面板的方式。
已验证的无效方法
我们尝试过以下三种方案,但均无法满足需求:
- 基于
transferSize的判断:
该方法在新版Chrome中完全失效,即便文档已被浏览器缓存,也从未返回var isCached = performance.getEntriesByType("navigation")[0].transferSize === 0;transferSize === 0的结果,推测仅适用于CSS、JS等非HTML资源。 - 通过导航类型判断:
var isCached = window.performance.navigation.type === 2;navigation.type === 2仅代表后退/前进导航行为,并非文档缓存的可靠指标——例如常规点击链接进入的页面也可能被缓存,但该方法无法识别此类场景。 - 服务器时间戳对比:
在文档中嵌入服务器生成的时间戳,前端通过对比当前时间判断是否缓存。但由于我们使用自带缓存的CDN,该方法无法区分文档来自CDN缓存还是浏览器缓存,因此失效。
可行解决方案
方案1:利用导航性能指标的时间差判断
当文档来自浏览器缓存时,浏览器无需向远端发起请求,responseStart与fetchStart的时间差会极小(通常小于1ms)。代码示例:
const navEntry = performance.getEntriesByType("navigation")[0]; // 可根据实际情况调整阈值,建议设为5ms以内 const isBrowserCached = navEntry.responseStart - navEntry.fetchStart < 1;
注意:需排除本地
file://协议的开发场景,部分浏览器可能存在微小误差,可适当放宽阈值。
方案2:结合缓存响应头与性能指标验证
先通过时间差初步判断,再验证文档的Cache-Control头是否允许浏览器缓存,进一步确认来源:
async function isFromBrowserCache() { const navEntry = performance.getEntriesByType("navigation")[0]; const timeDiff = navEntry.responseStart - navEntry.fetchStart; if (timeDiff < 1) { // 发起HEAD请求获取缓存策略头 const response = await fetch(window.location.href, { method: 'HEAD' }); const cacheControl = response.headers.get('Cache-Control'); // 判断是否符合浏览器缓存的策略 return cacheControl?.includes('max-age') || cacheControl?.includes('public') || cacheControl?.includes('private'); } return false; }
注意:HEAD请求可能触发缓存验证(如携带
If-Modified-Since头),需结合实际缓存策略调整逻辑。
方案3:配合CDN标识的多维度推断
利用CDN返回的server-timing头先区分CDN缓存和源站,再通过性能指标推断浏览器缓存:
function detectCacheSource() { const navEntry = performance.getEntriesByType("navigation")[0]; const timeDiff = navEntry.responseStart - navEntry.fetchStart; const serverTiming = navEntry.serverTiming; // 通过server-timing判断CDN或源站 const isCDNCached = serverTiming.some(entry => entry.name === 'cache' && entry.description === 'hit'); const isOrigin = serverTiming.some(entry => entry.name === 'cache' && entry.description === 'miss'); if (isCDNCached) return 'cdn'; if (isOrigin) return 'origin'; // 无CDN标识且时间差极小,判定为浏览器缓存 if (timeDiff < 1) return 'browser'; return 'unknown'; }
注意:该方案依赖CDN正确配置
server-timing头返回缓存状态。
内容的提问来源于stack exchange,提问作者Sven
相关产品推荐
相关产品推荐

