无需使用no-store,如何让浏览器后退按钮触发缓存验证?
浏览器的后退按钮依赖Back-Forward Cache(BF Cache,前后退缓存),这是一种内存级缓存机制,优先级远高于HTTP缓存规则,所以单纯配置Last-Modified和must-revalidate不会触发验证请求。以下是无需使用no-store的可行方案:
前端监听pageshow事件主动触发验证
当页面从BF Cache加载时,浏览器会触发pageshow事件,且event.persisted为true。利用这个特性,我们可以主动发起HEAD请求验证资源是否更新:window.addEventListener('pageshow', (event) => { if (event.persisted) { fetch(window.location.href, { method: 'HEAD', headers: { 'If-Modified-Since': document.lastModified } }).then(res => { if (res.status === 200) { window.location.reload(); // 资源已更新,刷新页面 } }); } });后端需正常返回
Last-Modified头,前端通过document.lastModified获取页面加载时记录的修改时间,与服务器端比对。用ETag替代/补充Last-Modified
ETag是资源的唯一标识(通常基于内容哈希生成),比Last-Modified更精确,能避免时间戳精度问题。后端返回ETag: "资源哈希值"和Cache-Control: must-revalidate,前端在验证时改用If-None-Match头:// 假设页面加载时存储了后端返回的ETag const pageETag = document.querySelector('meta[name="etag"]').content; window.addEventListener('pageshow', (event) => { if (event.persisted) { fetch(window.location.href, { method: 'HEAD', headers: { 'If-None-Match': pageETag } }).then(res => { if (res.status === 200) { window.location.reload(); } }); } });后端需在响应中返回ETag,并在收到
If-None-Match请求时比对,匹配则返回304,不匹配则返回200和新资源。限制BF Cache的存储(谨慎使用)
空的unload事件会阻止浏览器将页面存入BF Cache,结合Cache-Control: no-cache, must-revalidate,可强制后退时走HTTP缓存验证流程:window.addEventListener('unload', () => {});注意:此方法会失去BF Cache的快速页面恢复能力,仅适合对实时性要求极高的页面。
后端优化Cache-Control配置
保留Last-Modified/ETag的同时,设置合理的max-age和must-revalidate:Cache-Control: max-age=3600, must-revalidate Last-Modified: Wed, 21 Oct 2024 07:28:00 GMT这能让普通导航场景下利用缓存提升性能,而后退场景则通过前端事件触发验证,兼顾性能与新鲜度。
内容的提问来源于stack exchange,提问作者Joe Yahchouchi

