Nginx 不转发后端返回的 304,因其要求上游响应含完整 body,而 304 规范禁止携带 body,故默认拒收并报 502;正确做法是后端返回带 Last-Modified/ETag 的 200,由 Nginx 自主生成 304。

nginx 本身不生成 304 响应,也不会“处理”后端返回的 304 —— 它根本不会把 304 转发给客户端。这是关键前提。
nginx 对后端 304 的实际行为
当 nginx 作为反向代理(例如用 proxy_pass)时,如果上游服务器(如 Node.js、Django、Tomcat)直接返回了 304 状态码,nginx 默认会拒绝转发该响应,并返回 502 Bad Gateway 或静默丢弃,因为:
- nginx 的代理模块(ngx_http_proxy_module)要求上游必须返回完整响应体(含 body)才能被正常透传;而 304 规范明确禁止携带响应体;
- nginx 在收到无 body 的 304 后,无法构造合法的 proxy 缓存键或填充必要头部,会判定为协议违规;
- 日志中通常出现 "upstream sent no valid HTTP/1.0 header" 或 "upstream prematurely closed connection" 类错误。
为什么后端不该直接返回 304 给 nginx
304 是专为终端浏览器设计的协商缓存响应,其语义依赖于客户端已持有完整资源副本 + 有效条件请求头(If-Modified-Since / If-None-Match)。但 nginx 作为中间层:
- 不保存原始资源内容,无法验证“未修改”是否成立;
- 若上游擅自返回 304,等于绕过 nginx 的缓存控制逻辑(如 proxy_cache、expires),导致缓存策略失效;
- 违反 HTTP 分层职责:协商缓存应由最靠近用户的组件(浏览器或 nginx 自身)完成,而非交由后端决策。
合规的替代方案:让 nginx 主导 304 决策
正确做法是:后端始终返回 200 + 完整内容 + 合规的校验头(Last-Modified 和/或 ETag),由 nginx 根据这些头自主判断并生成 304。配置要点包括:
- 启用 proxy_cache 并设置 proxy_cache_valid 200 302 1h;;
- 确保后端响应含 Last-Modified(基于文件 mtime)或强 ETag(如 SHA256 内容哈希);
- 在 location 块中添加:
proxy_ignore_headers Last-Modified ETag;
proxy_cache_use_stale off;
add_header X-Cache-Status $upstream_cache_status; - nginx 收到带 If-Modified-Since 的请求后,会比对缓存中的 Last-Modified 值,匹配则自动生成 304,不触达后端。
头部合规性审计要点
若仍需调试上游误发 304 的场景,可抓包检查其响应是否满足 RFC 7232 要求:
- 必须不含 Content-Length、Content-Encoding、Transfer-Encoding 等 body 相关头;
- 可包含:Cache-Control、Expires、Vary、ETag(仅当与 If-None-Match 匹配时)、Last-Modified(仅当与 If-Modified-Since 匹配时);
- 禁止出现 Location、Content-Type、Set-Cookie 等 200 常用头;
- 响应体必须为空(0 字节),且不能有额外换行或空格。


















