跳到主要内容
xzzlog

HTTP 304 为什么没有正文,ETag 和 Cache-Control 怎么配合

304 表示缓存验证通过,不是空白页面错误。用 GET 请求检查 ETag 与条件请求,区分 no-cache、no-store 和共享缓存,避免缓存个人数据。

文章目录
LisaHost:原生与住宅IP产品,按套餐选择
大陆访问,精品线路|搬瓦工 · CN2 GIA / CTGNet 套餐
腾讯云:锐驰型200Mbps峰值带宽,中国内地2核2G50元每月
野草云:香港200Mbps峰值带宽,不限月流量,30元每月起
RackNerd:海外VPS21.99美元每年起
云服务器,积分可续期|雨云 · 国内外节点 · 积分兑换权益
DMIT:Premium中国大陆优化线路CN2GIA
WorkBuddy:交代任务,交付文件
BRNCHost:Bursa土耳其游戏服务器,1Gbps端口,DDoS防护
Evoxt:最高6.0GHz CPU,2.99美元每月起
晚安云:香港云服务器2核2G15元每月
京东云:AI进入真实业务

浏览器网络面板出现 304,响应体里没有 HTML,页面却照常显示。这通常是浏览器已经有一份缓存,本次只向服务器确认它是否还能用。304 不需要再次传同一份正文;如果缓存本身不存在,问题就要沿请求链继续查。

从一次普通 GET 开始

对自己有权检查的公开页面运行:

curl -sS -D response-headers.txt -o response-body.html \
  'https://site.example/article'

域名与路径需要替换。使用 GET 而不是仅看 HEAD,可以同时确认正文与缓存响应。留意状态码、ETag、Last-Modified、Cache-Control、Vary;经过 CDN 时也记录服务商的缓存状态字段。

ETag 是服务器给某个响应表示分配的验证标识,客户端不应自己猜它等于文件哈希。相同网址还可能因语言、压缩或认证产生不同表示,不能只记一份正文就解释所有请求。

条件请求带回原来的标识

从响应里复制真实 ETag,保留引号及可能存在的 W/ 前缀。下面的值是演示:

curl -sS -D recheck-headers.txt -o recheck-body.html \
  -H 'If-None-Match: "demo-version-1"' \
  'https://site.example/article'

对于 GET,在条件匹配等适用情况下,服务器可以返回 304。它表示使用已有表示;如果响应变化,应返回新正文及对应验证信息。演示值不匹配真实页面时,得到 200 很正常。

排查时对齐请求方法、Cookie、语言与编码条件。终端请求没有浏览器原先的缓存上下文,单独拿到一个 304 也不会自动拥有那份 HTML。

no-cache 不等于不保存

no-cache 允许保存,但复用前需要按规则向服务器验证;no-store 要求缓存不要存储该响应。private 限制共享缓存,仍可能允许用户自己的浏览器缓存。max-age 表示新鲜期,不能把它理解成文件在所有设备上到点同时消失。

登录后的账单、账号资料或管理页面,需要按实际数据制定缓存规则。仅给个人响应加 ETag,不会自动阻止 CDN 把它存成公共页面。配置变更也不一定清掉先前已经存在的副本,应检查整个共享缓存路径和失效方式。

Vary 用来表达选择响应表示时涉及的请求字段。若内容依赖语言而缓存键没有区分,用户可能收到另一语言版本。随意增加大量 Vary 字段也会影响命中率,按实际差异设置。

状态码之外再看正文来源

页面显示旧内容时,分别确认浏览器副本、CDN、副本服务器和源站。一次刷新成功,不能证明所有地区缓存都更新;也不要给每个请求附随机参数,就宣布缓存规则正确。

保存一次首次获取和一次条件请求,比较状态码、验证标识与实际正文。规则含义见 HTTP 缓存标准 RFC 9111,条件请求见 HTTP 语义 RFC 9110。需要查请求时间时,再看 curl 的时间分段。

继续阅读 返回顶部