协商缓存由服务端通过Last-Modified/If-Modified-Since或ETag/If-None-Match响应头与请求头配合实现,JavaScript仅能间接影响;需搭配Cache-Control: no-cache强制进入协商流程,且服务端必须严格字符串比对。

协商缓存不是靠 JavaScript 主动设置响应头,而是由服务端在 HTTP 响应中写入特定头字段,浏览器自动配合发起条件请求。JavaScript 的作用是配合逻辑(比如控制 Ajax 是否走协商流程),但真正“精准控制”的关键在服务端响应头的设计与比对逻辑。
核心响应头:Last-Modified 与 ETag
这两组头字段分别对应两种协商机制,不能混用,需按资源特性选其一:
-
Last-Modified / If-Modified-Since:适合文件类资源(如 HTML、CSS、图片)。服务端返回文件系统修改时间(
mtime),转为标准 GMT 字符串,例如Wed, 21 Oct 2025 07:28:00 GMT;浏览器后续请求自动带If-Modified-Since,服务端必须做严格字符串全等比对(不能解析成 Date 再比毫秒)。 -
ETag / If-None-Match:更适合动态内容或无法精确获取修改时间的场景。ETag 是服务端生成的唯一标识(如哈希值
"abc123"或版本号"v2.1.0"),浏览器下次请求带If-None-Match,服务端直接比对字符串是否一致即可。
服务端设置要点(以 Node.js 为例)
响应头本身不难写,但细节决定成败:
Java Maven 项目审查工作流的通用输入处理。当 Java Maven 项目以 ZIP压缩包或 GitLab 仓库 URL 形式提供且需要...时使用。
- 用
fs.statSync(path).mtime.toUTCString()获取并格式化时间,避免时区或格式偏差; - ETag 建议用强一致性算法生成(如
crypto.createHash('md5').update(content).digest('hex')),静态资源也可用构建时注入的 hash 值; - 务必搭配
Cache-Control: no-cache,明确跳过强缓存,强制进入协商流程; - 若用 Webpack Dev Server、Vite 或 Nginx,需确认中间层未覆盖或删除这些头——CDN 或反向代理常默认剥离
Last-Modified。
Ajax 请求如何确保走协商缓存
浏览器对普通资源(如 script、link)自动处理协商逻辑,但 Ajax 默认可能启用强缓存(尤其 GET 请求),需手动干预:
立即学习“Java免费学习笔记(深入)”;
- fetch 中设
cache: 'no-cache':触发带If-None-Match或If-Modified-Since的条件请求; - XMLHttpRequest 中调用
setRequestHeader('Cache-Control', 'no-cache')(注意跨域时需服务端允许该 header); - 若服务端未支持 ETag/Last-Modified,可在 URL 后加时间戳参数(如
?t=1723575180)作为兜底,但这属于绕过缓存,不是协商。
常见失效原因与规避方式
304 没返回、总是 200、缓存“假命中”,往往源于这几个细节:
- Last-Modified 精度只有秒级:同一秒内多次改文件,浏览器可能收不到更新——高频变动数据优先选 ETag;
- 大小写或连字符错误:
if-modified-since是小写带连字符,服务端取值别写成If-Modified-Since; - 服务端比对逻辑出错:比如用
new Date(req.headers['if-modified-since']) === new Date(mtime),因解析误差或时区导致失败; - 前端发请求时禁用了缓存(如 fetch 加了
cache: 'no-store'),那就根本不会触发协商。

















