304状态码表示客户端发起条件请求后,服务端验证资源未修改,故不返回实体内容而仅返回304响应;其触发依赖服务端首次响应提供Last-Modified或ETag,客户端后续请求携带对应If-Modified-Since或If-None-Match头,且服务端正确比对并返回304。

触发 304 状态码,核心是让浏览器发起一个条件请求,且服务端根据请求头判断资源未修改,于是不返回实体内容,只返回 304 响应。
客户端必须发送有效的条件请求头
浏览器不会自动发条件请求,得靠你主动设置或依赖已有缓存行为。关键看两个响应头怎么来的:
-
Last-Modified:服务端在首次响应中带上
Last-Modified: Wed, 21 Oct 2023 07:28:00 GMT;之后浏览器再次请求时,自动附上If-Modified-Since: Wed, 21 Oct 2023 07:28:00 GMT -
ETag:服务端返回
ETag: "abc123"(强校验)或ETag: W/"xyz789"(弱校验);后续请求带If-None-Match: "abc123"
只要其中一组匹配(优先级:ETag > Last-Modified),且服务端验证通过,就可返回 304。
服务端必须正确校验并返回 304
服务端收到 If-Modified-Since 或 If-None-Match 后,不能忽略,要主动比对:
立即学习“Java免费学习笔记(深入)”;
- 对
If-Modified-Since:检查资源最后修改时间是否 ≤ 请求头时间,是则返回 304 - 对
If-None-Match:检查当前 ETag 是否与请求值一致,一致则返回 304 - 注意:若两者都存在,
If-None-Match优先;任一不满足,就按常规流程返回 200 + 内容
确保请求走的是缓存路径,不是禁用缓存
以下情况会阻止 304 触发:
- 响应头含
Cache-Control: no-cache:浏览器仍会发请求,但必须带条件头(所以 304 仍可能);而no-store则完全不缓存,也不发条件请求 - 手动刷新(F5)通常保留条件头,但强制刷新(Ctrl+F5)会加
Cache-Control: no-cache并清空条件头,导致发无条件请求 → 返回 200 - 地址栏回车、链接跳转、前进/后退:默认复用缓存,最易触发 304
调试时怎么看是否真走了 304
别只看 Network 面板状态码,还要确认:
- 请求方法是 GET(HEAD 也可,但实际极少)
- 请求头里有
If-Modified-Since或If-None-Match - 响应头没有
Content-Length或Content-Type(304 不允许带响应体) - 响应头包含
Cache-Control、ETag、Last-Modified等字段(说明服务端支持协商缓存)


















