304状态码能省抓取预算,142个站只有52个回得出

304状态码能省抓取预算,142个站只有52个回得出
张文保 80 分钟阅读 4,918 阅读
本文目录
  1. Google那句建议的原文到底说了什么?
  2. 它写在哪一份文档的哪一节
  3. 原话的三个要点
  4. 这条建议的收益到底该怎么算
  5. 它跟抓取频率是什么关系
  6. 为什么这条建议和其它建议不一样?
  7. 平台介入的第三种方式
  8. 三十秒的判据
  9. 亲自型的投入曲线是线性的
  10. 没有反馈这件事有多要命
  11. 所以它的失败模式是“一直没做”
  12. 一次条件请求究竟在问什么?
  13. 整个流程分两步
  14. 两种凭据的差别比想象中大
  15. 弱校验在这里是加分项
  16. 最容易被误解的一点
  17. 还有一个概念也常被混淆
  18. 为什么这套机制没被更广泛地实现
  19. 第一关:142个站里有多少个能被问?
  20. 怎么测的
  21. 七次请求分别在测什么
  22. 并发和礼貌
  23. 被排除的那69个是什么情况
  24. 结果
  25. 这四成里大部分是主动放弃的
  26. 剩下那部分才是真的漏了
  27. 怎么区分自己属于哪一类
  28. 顺带说说Vary这个头
  29. 第二关:那张凭据稳不稳?
  30. 连发两次,看凭据变不变
  31. 这件事没有任何指标会报警
  32. 为什么两次之间要留几秒
  33. Last-Modified那两个不一致的更奇怪
  34. 节点不一致这件事的连带影响
  35. 从ETag的形状能读出什么根因?
  36. 第一类:长度段不变,哈希段在变
  37. 这个推断为什么可以直接用
  38. 第二类:整条ETag的格式都变了
  39. 第三类:缓存键相同但摘要不同
  40. 三类合起来的启示
  41. 这套读法可以推广到别处
  42. 顺便说一个反面教训
  43. 第三关:真发条件请求,回不回304?
  44. 拿ETag去问
  45. 拿时间去问
  46. 再补一个额外测的场景
  47. 合起来看
  48. 这个漏斗的形状值得看一眼
  49. 那52个通过的站有共同点吗
  50. 这三成六该怎么解读
  51. 省下来的量有多大
  52. 那25个不认自己凭据的站最值得说
  53. 那4个返回跳转的又是另一回事
  54. 首页骗了你
  55. 换一批地址重测
  56. 差了将近一倍
  57. 这个差别对怎么排查有直接影响
  58. 为什么内页样本只有90个
  59. 顺带说说怎么挑内页样本
  60. 这条对照给出的实操结论
  61. 这个对照也改变了整篇文章的结论
  62. 内页那一轮的另外两个发现
  63. 那个最后修改时间,填的到底是什么?
  64. 两次请求,时间倒着走
  65. 两种成因
  66. 怎么一眼看出自己有没有踩这个坑
  67. 动态页面该从哪取这个时间
  68. 一个折中办法
  69. 说了别缓存,又给了凭据
  70. 35个站里有6个前后不一致
  71. 这种矛盾是怎么来的
  72. 矛盾的实际后果是什么
  73. 怎么快速看一眼自己的响应头
  74. 顺带一个更普遍的数字
  75. 各条指令的实际使用分布
  76. 这两条指令经常被混用
  77. 爬虫换一种方法问,你的站答得上来吗?
  78. 官方确认过的方法清单
  79. 只要响应头的那种请求
  80. 为什么不给内容长度是个问题
  81. 询问支持哪些方法的那种请求
  82. 那些写入类的方法要不要管
  83. 按服务器类型看这三关的通过率
  84. 基础设施决定默认值这件事的普遍性
  85. 换服务商的时候尤其要重测
  86. 三条检查项凑成一份迁移清单
  87. 自检和修复一共几步?
  88. 三分钟的自检
  89. 测竞争对手这件事顺带说两句
  90. 顺带能测出来的其它东西
  91. 这套自检有一个前提
  92. 四种失败对应四种修法
  93. 每一类的实际改动长什么样
  94. 先修哪一类
  95. 修完之后怎么验收
  96. 把它挂进哪个流程
  97. 三个反直觉的判断
  98. 三篇合起来的那条线
  99. 如果只能记住一件事
  100. 最后留一句给做技术SEO的人
  101. 这套自检值多少钱
  102. 跟别的抓取预算动作比,它排第几
  103. 什么情况下可以直接跳过
  104. 常见问题解答
  105. 支持304会不会让用户看到旧内容?
  106. 我的站不大,值得做这个吗?
  107. 返回304的时候,响应头还要带哪些字段?
  108. 页面里有CSRF令牌,还能支持ETag吗?
  109. 怎么判断我的ETag是渲染前算的还是渲染后算的?
  110. ETag和Last-Modified该给哪个,还是都给?
  111. 为什么我的ETag每次请求都不一样?
  112. Search Console里能看到这一项吗?
  113. 用了CDN,这件事还归我管吗?
  114. 拿首页测出来的结果可信吗?
  115. 最后修改时间该填什么值?
  116. 爬虫真的会发那些不常见的请求方法吗?
  117. 声明了no-store的站怎么办?
  118. 权威参考资料

摘要:对211个国际化电商域名各发了七次请求,看它们在被问“这个页面变了没有”的时候答不答得上来。首页这一层,142个能正常响应的站里只有52个回得出304,占36.6%;四成的站连一个可以拿来协商的凭据都不给。更麻烦的是有25个站给了ETag却不认自己发的ETag,重发照样全量返回。另外还有16个站连发两次拿到的ETag就不一样,其中五个的字节长度段一模一样、只有哈希段在变。

Google在管理抓取预算的官方文档里,有一条建议写得很短:支持304状态码。如果一个页面自上次抓取以来没有变化,返回304就等于告诉Google复用缓存那一份,替你省下服务器带宽和资源。

这条建议很好懂,也很容易被跳过。因为它跟同一份文档里的其它建议不太一样——它不在Search Console里,不在任何一份报告里,没有一个检查会告诉你做到了没有。

那到底有多少站真的做到了。保哥把手上那批国际化电商域名拿来实测了一轮:先正常请求一次拿凭据,再拿着凭据重发,看它回什么。结论是三成六。而这三成六背后的故事,比这个数字本身有意思得多。

这篇文章的前半段讲机制:条件请求到底在问什么、这条建议属于哪一类规则、为什么它没有任何反馈。后半段是实测的四道关卡,以及一份能用一条命令跑完的自检。

Google那句建议的原文到底说了什么?

先把原文和它所在的位置摆清楚,因为这决定了它的分量。

回原文核对是这个系列反复强调的动作,七万五千条答案实证的引用偏好也是靠原始数据说话。

它写在哪一份文档的哪一节

这条建议出现在大型站点抓取预算管理指南里,属于“减少抓取预算浪费”那一节。同一节下面还有另外八条建议,包括合并重复内容、用规则屏蔽不必要的页面、给永久删除的页面返回404或410、消除软404、保持站点地图更新、避免重定向链、优化页面加载速度、以及排查抓取问题。

同一份文档里其余八条建议怎么落地,抓取预算优化的十二项实操指南里逐条拆过,可以配着这一条一起做。

把这九条排在一起看,会发现支持304这一条的位置很特别:其余八条都是内容侧或者信息架构侧的活,只有它是纯服务端行为。

原话的三个要点

原文一共三句话,拆开是三层意思。

抓取这一侧的硬约束不止一条,Googlebot抓取2MB限制的八步实战优化是另一条会直接卡住内容的限制。

第一层是动作:支持304这个状态码。第二层是条件:当一个页面自上次抓取以来没有变化的时候。第三层是收益:告诉Google复用它缓存的那一份,从而节省你的服务器带宽和资源。

请注意第三层的措辞:省的是你的带宽和资源,不是Google的。这句话的主语很关键——它没有承诺你会被抓得更勤,也没有承诺收录会变快。它承诺的只有一件事:同样的抓取次数,你少发很多字节。

这条建议的收益到底该怎么算

很多人一看到抓取预算就想到收录速度,然后期待一个排名或者流量层面的回报。这个期待多半会落空。

页面体积直接决定这笔账有多大,四十六个电商站的页面体积实测量的正是同一批站的字节规模。

更实际的算法是这样:你的服务器每天为爬虫发出去多少字节,其中有多少是重复发送的完全相同的内容。本次实测里,142个站的首页平均大小是707 KB,全部加起来一次就是98 MB。如果一个爬虫每天来抓十次而内容一次都没变,那就是十次707 KB。

支持304之后,这十次里的九次可以压缩成一个空响应。省下来的不是抽象的预算,是实实在在的出口带宽和数据库查询。对流量大的站,这笔账相当可观;对小站,说实话省不了几个钱,但它也几乎不花什么力气。

还有一层收益不太容易量化但确实存在:返回304的响应,服务端往往不需要走完整的渲染流程。一个动态页面的全量响应可能要查十几次数据库、跑一遍模板、再做一次压缩;而一次304只需要比对一个字符串。这部分省下来的计算资源,在大促这类高峰时段的价值远超带宽本身。

它跟抓取频率是什么关系

这是个高频误解,值得说清楚。支持304不会直接让Google抓得更勤,官方也没这么承诺过。

抓取频率的真实情况只能从日志里看,日志分析一步步挖出AI爬虫真相给了一套可复用的分析顺序。

但它们之间有一层间接联系:抓取速率的上限,一部分取决于系统观察到的你的服务器响应状况。如果你的站响应快、错误少,系统会更愿意多抓;而全量返回一个大页面比返回一个空的304慢得多。

所以合理的预期是:这条建议的主要收益在你自己这一侧,抓取侧的收益是次生的、不确定的、也没法单独归因。把它当成一件降本的事去做,比当成一件提效的事去做更不容易失望。

为什么这条建议和其它建议不一样?

这是前两篇文章里那个三分法的第三格,也是最容易被忽略的一格。

这三类规则背后是同一套身份与信任机制,实体主页怎么搭才算把品牌身份立住给了整体框架。

平台介入的第三种方式

前面两篇分别讲了禁止型和代劳型:禁止型是平台立规矩、违反了要挨罚;代劳型是平台自己算、你只能摆原料。这一篇讲第三种,可以叫亲自型——这件事百分之百发生在你的机器上,平台只能建议,做与不做只有你自己知道。

第一类禁止型的样本是名字字段,商家名称禁令当尺子量出来的那份结果是这个系列的第一篇。

类型发生在谁那儿官方措辞失败怎么被发现
禁止型平台的库里不被允许、可能导致收到处罚通知
代劳型平台的算法里偏好、支持、会考虑看展示结果不对
亲自型你的服务器上我们建议、请支持永远不会被通知

同一批电商站的另一项体检也是这个量级,四十个电商站的站内搜索页实测可以并排看。

三十秒的判据

判断一件事是不是亲自型,问两个问题就够。

第二类代劳型的样本是图标与站点名称,favicon要上广告位而两百多个站拿不出图是这个系列的第二篇。

第一个问题:这件事发生在谁的机器上。发生在你这边的,平台只能建议,因为它没有任何执行手段——它总不能替你改服务器配置。

第二个问题,也是更好用的那个:有没有一个官方工具能告诉你做到了没有。有的话,说明平台在意这个结果、并且愿意为你提供反馈;没有的话,那这件事就完全是你自己的事。

条件请求这一条,两个问题都指向亲自型。Search Console里没有这一项,富媒体测试工具里没有,页面体验报告里也没有。你唯一的检查手段是自己发一次请求。

亲自型的投入曲线是线性的

这一点跟前两类差别很大。禁止型是阶跃:过线之前为零,过线之后不再增长。代劳型是钝的:收敛候选很有用,超出之后无效。亲自型是线性的:做多少得多少,而且不封顶。

服务端这一层的活基本都属于做多少得多少,服务器配置对SEO影响的二十项清单里全是这一类。

为什么线性,因为它省下来的东西是按次计的。你的站被抓得越频繁、页面越大、变更越少,这条建议的收益就越高。这也是为什么它写在“大型站点”那份文档里——规模本身就是它的乘数。

也正因如此,它是三类里唯一一个值得长期投入的。禁止型做完就该走人,代劳型收敛完就该停手,只有亲自型的活会随着你的站变大而持续升值。

没有反馈这件事有多要命

把三类规则的反馈机制并排看,差别一目了然。

没有反馈的时候只能自己造一个观测,给那条建议配一个注定无效的对照组讲的就是怎么造。

禁止型有明确的通知:资料被暂停会发邮件,手动操作会在后台显示,你不可能不知道。代劳型虽然没有通知,但结果是肉眼可见的——搜索一下自己的品牌,图标和名字对不对一目了然。

亲自型两样都没有。做与不做,页面表现完全一样;做错了和做对了,浏览器里看不出任何区别。你的服务器可能已经连续三年在为爬虫重复发送同样的几百KB,而没有任何一个系统觉得这值得提一句。

所以它的失败模式是“一直没做”

其它两类规则的失败通常是一次性事件:某天改错了、某天被罚了。亲自型的失败是一种持续状态——它从上线第一天起就没做,然后一直没做,中间没有任何一个时刻会变糟,也就没有任何一个时刻会引起注意。

持续状态的失败最难被注意到,用户扫完一整屏一个都没点开这件事也是同一种静默。

这解释了本次实测的一个现象:做到和没做到的分布,跟站点规模、品牌知名度、技术水平的相关性都不强,反而跟“用的是哪套基础设施”高度相关。因为绝大多数团队从来没主动做过这个决定,最终结果就是它们的服务商替它们做了。

一次条件请求究竟在问什么?

要看懂后面的数据,得先把机制过一遍。这套东西不复杂,但有几个反直觉的点。

机制讲清楚了才知道报表在说什么,hreflang备用网址被当成规范页别名也是先把机制拆开。

整个流程分两步

第一步,客户端正常请求一个地址,服务端返回内容,同时在响应头里附上一张或两张“凭据”。凭据有两种:一种叫 ETag,是这份内容的一个标识符;另一种叫Last-Modified,是这份内容的最后修改时间。

抓取与渲染分几步直接影响服务端要付出多少,搜索引擎抓取和渲染DOM分几步把这条链路拆开讲过。

第二步,客户端下次再来的时候,把凭据带上:拿ETag的用If-None-Match这个请求头,拿时间的用If-Modified-Since。服务端比对之后,如果内容确实没变,就返回304和一个空的响应体;变了就返回200和完整内容。

这套机制的正式定义在 HTTP语义规范里条件请求那一章,缓存相关的部分则在另一份专讲HTTP缓存的规范里。

两种凭据的差别比想象中大

ETagLast-Modified
本质内容的标识符一个时间戳
精度可以精确到字节最细只到秒
生成成本通常要读一遍内容读一下文件属性即可
失效风险内容含随机成分就永远变时间戳被写成当前时间就永远变
本次实测覆盖率54.2%12.7%

响应头这一层的能力比多数人以为的多,用内容协商给AI交付Markdown的实操是另一个用法。

规范里还区分了强校验和弱校验:ETag前面带W斜杠前缀的是弱校验,表示两份内容语义等价但字节未必完全相同。本次样本里绝大多数ETag都是弱校验,这很正常,因为动态生成的页面很难保证字节级一致。

弱校验在这里是加分项

很多人看到弱校验会觉得不严谨,其实反过来。弱校验允许你说“这两份内容语义上是一样的”,即使它们的字节不完全相同。这正好是动态页面需要的能力。

想看别人的响应头怎么配,十款网站技术栈检测扩展的实测对比里有能直接读的工具。

理论上,一个实现得好的服务端可以主动利用这一点:把页面里那些不影响语义的部分——随机令牌、请求编号、渲染时间戳——排除在哈希计算之外,然后打上弱校验标记。这样即使字节变了,标识符也不变,条件请求照样能生效。

本次实测里没有看到有站这么做。那五个长度段不变、哈希段变的站,用的都是对整个响应体做哈希的默认实现。它们打了弱校验的标记,行为却是强校验的。标记和实现不一致,这是另一种形式的名不副实。

这也给出了一条很具体的改造思路:你不一定要把随机令牌从页面里挪走,只要把它排除在哈希计算之外就行。前者要动前端和后端的交互方式,后者只需要改一处哈希逻辑,成本差好几倍。

最容易被误解的一点

很多人以为返回304就等于“这个页面被缓存了”,然后担心内容更新之后用户看到旧版。这是两件事。

缓存与索引状态经常被混为一谈,已收录页面加noindex后多久消失的六大场景实测把这两件事分开量过。

缓存策略由Cache-Control这类响应头决定,它说的是“这份内容可以被存多久”。条件请求说的是“存着的那份还能不能用”。前者决定要不要问,后者决定问了之后怎么答。

所以支持304完全不影响内容的时效性——内容真变了,服务端就返回200和新内容,一秒钟都不会延迟。它省的只是那些确实没变的时候的重复传输。

还有一个概念也常被混淆

304和200之间还夹着一个容易被忽略的区别:304不是“这个页面没变”,而是“你手上那份还能用”。主语是客户端手上的副本,不是页面本身。

概念混用是很多错误结论的起点,一条五年趋势线上有三处口径变更就是一次口径混用的代价。

这个区别在实践里有意义。假设一个页面被改了又改回来,字节完全恢复原样,那么ETag也会恢复原样,条件请求照样返回304,而中间那次改动对客户端来说等于没发生过。这套机制关心的是等价,不是历史。

反过来的情况也存在,而且更常见:内容在语义上完全没变,字节却变了。页面里换了个随机令牌、请求编号变了一位、某个时间戳精确到了秒,这些都不影响任何人读到的东西,但足以让整份内容的哈希彻底改变。

这就是后面那批数据的核心矛盾:一个用来判断“是不是同一份内容”的机制,实际判断的是“是不是同一串字节”,而这两者在动态页面上经常对不上。规范给了弱校验这条出路,可惜实测里几乎没人真的用起来。

为什么这套机制没被更广泛地实现

说一句公道话:对静态文件来说这件事几乎是白送的,服务器自动就做了;难的是动态页面。

静态与动态的差别决定了这件事的难度,SaaS托管自建与纯代码的选型全拆解里有各类栈的对比。

动态页面要生成ETag,服务端得先把整个响应体渲染出来,才能算出哈希——而渲染本身就是最贵的那一步。算完哈希发现可以返回304,省下的只是网络传输,计算已经花掉了。

要真正省掉计算,得在渲染之前就知道内容有没有变,这需要一个可靠的版本标识:内容的更新时间戳、缓存条目的版本号、或者数据层的变更序号。这一步是有设计成本的,也是大多数站停在半路的地方——它们生成了ETag,但那个ETag是渲染完之后算的。

第一关:142个站里有多少个能被问?

要回答“变了没有”,你首先得给出一个可以拿来比对的凭据。这一关卡住的站比预想的多。

能不能被问取决于你有没有给出可引用的东西,GSC品牌词过滤器的五步使用指南里那套拆分也依赖你先给出可用的标记。

怎么测的

对211个域名的首页各发一次普通请求,跟随跳转,从最终那个响应的头里读ETag、Last-Modified、Cache-Control、Vary、Server这几项。211个里有142个返回了200,其余是人机验证、跳转或者连不上,不进统计。

批量发请求并读响应有现成的做法,网站死链怎么批量查出来的一条龙流程可以直接改来用。

有一个技术细节值得交代:响应头必须取最后一个响应块的,不能取第一个。因为跟随跳转的时候,会依次收到跳转响应的头和最终响应的头,两者的ETag和缓存策略往往完全不同。如果取错了,测的就是跳转那一跳的行为,跟内容页没关系。

这一步在写脚本的时候特别容易搞错,而且错了之后数据看起来完全正常——你会得到一批合法的、但描述的是另一个东西的响应头。这类错误的隐蔽性跟本文后面要讲的那几个问题是同一个性质。

七次请求分别在测什么

每个地址一共发七次,各有分工,列出来方便你自己复现。

测法设计决定结论能不能用,三百个站实测出来的收录速度指标怎么读里有同一类的设计说明。

第几次发什么测什么
第一次普通请求拿凭据、拿缓存策略、拿体积
第二次同样的普通请求凭据稳不稳
第三次带上第一次拿到的ETag认不认自己发的标识符
第四次带上第一次拿到的时间认不认自己发的时间戳
第五次带一个一小时前的时间没有凭据时能不能答
第六次只要响应头的那种请求换个方法答不答得上来
第七次问支持哪些方法规范里那一条有没有实现

七次里前五次是这篇文章的主线,后两次是顺带。如果你只想自查,跑前三次就够了,两分钟。

换一种口径去看,缺口才会显形,日志里带人来的其实是另一批入口是同一种发现方式。

并发和礼貌

顺带说一句抓取礼仪。本次是二十多个并发跑完两百多个域名的七次请求,总请求量一千五百次左右,对每个站来说就是七次,负载可以忽略。

被防护层当成可疑流量是很常见的事,五种代码识别搜索引擎蜘蛛的实战指南从另一侧解释了判定逻辑。

但如果你要做更大规模的测量,请把并发限制在合理范围,并且给同一个域名的请求之间留间隔。本次有4个域名返回了限流状态码,说明防护层确实在盯着。被限流不只是拿不到数据的问题,它还会污染你的样本——被限流的站会掉出统计,而它们未必是随机掉的。

被排除的那69个是什么情况

211减去142,还剩69个没进统计。分布是:返回拒绝访问的34个、完全连不上的20个、停在跳转上的8个、被限流的4个,剩下几个是各种其它状态。

被排除的样本会悄悄改变结论边界,调研数据里没有一个非会员却写给非会员看是这一类的典型。

拒绝访问那34个绝大多数是人机验证——本次抓取用的是普通浏览器标识,被防护服务拦下很正常。这批站不是没做,是没让我测。它们对真实爬虫的行为可能完全不同,所以本文所有比例都只代表能被正常访问的那142个。

这个偏差的方向不好判断。一方面,上了严格防护的站通常技术投入更高,可能做得更好;另一方面,防护层本身也会改变缓存行为。说不清方向的偏差,就只能如实标出来,别假装它不存在。

结果

凭据情况站数占142的比例
有ETag7754.2%
有Last-Modified1812.7%
两个都有107.0%
一个都没有5740.1%

四成的站,连被问的资格都没有。爬虫想问一句“这页变了没有”,找不到任何可以引用的东西,只能整页重下。

这四成里大部分是主动放弃的

翻了一遍这57个站的响应头,发现一个很清楚的规律:其中相当一部分的Cache-Control里写着no-store或者no-cache。

保守策略是有代价的,支付页CSP实测五十三个站的出厂默认里有同一种权衡。

no-store的意思是“任何环节都不要存这份内容”。既然不让存,那也就没有“存着的那份还能不能用”这个问题,不给凭据在逻辑上是自洽的。这批站不是没做好,是明确选择了不参与这套机制。

这个选择通常出于两个理由:一是首页高度个性化,每个人看到的都不一样;二是安全或合规要求,不希望任何中间节点留存内容。理由都成立,但代价是每一次抓取都是全量。

剩下那部分才是真的漏了

另一部分站的Cache-Control写的是public加一个不小的max-age,明确表示这份内容可以被缓存很久——但它一个凭据都不给。

自相矛盾的配置该在上线前拦下来,新网站前十二周的技术地基清单里有对应的检查项。

这就自相矛盾了:你说这份内容可以存一个小时,可你没给任何办法让人确认这一个小时之后它还是不是原来那份。缓存到期之后,客户端只能整页重下,前面那个max-age相当于白设。

这一类才是真正意义上的疏漏,而且修起来最简单——绝大多数服务器和CDN都支持自动生成ETag,通常就是一个开关。

怎么区分自己属于哪一类

看两个头就够了。如果Cache-Control里有no-store,那是主动放弃,不用管;如果写的是public加一个max-age,或者干脆什么都没写,而同时又没有任何凭据,那就是疏漏。

一条记录背后的展开规则往往不由你定,SPF记录只有一行展开要查几次是别人定的是同一类隐性约束。

本次142个站里,没有Cache-Control这个头的有70个,接近一半。这一档最尴尬:它既没有明确说可以缓存,也没有明确说不要缓存,缓存行为完全交给各个客户端按启发式规则去猜。

猜的规则通常是这样:客户端拿最后修改时间和当前时间的差算一个比例,得出一个自己觉得合理的缓存时长。而如果你连最后修改时间也没给,那这套启发式也用不上,结果就是每次都重下。

顺带说说Vary这个头

还有一个容易被忽略的相关项。Vary声明的是“这份响应的内容会随哪些请求头变化”,比如随语言变、随设备变、随压缩方式变。

同一份内容对不同客户端呈现不同版本,浏览器自动翻译把选项改掉而问卷看不出异常是个极端案例。

它跟条件请求的关系是:如果你的内容真的会随某个请求头变,那就必须声明,否则缓存层可能把A用户的版本拿给B用户。但反过来,Vary声明得太宽也有代价——每多一个变量,缓存的命中率就降一档。

本次没有对Vary做详细统计,只在读头的时候顺带记录了。写在这里是提醒你,条件请求这件事不是孤立的,它和缓存策略、内容协商是同一套东西的三个侧面。

第二关:那张凭据稳不稳?

给了凭据只是第一步。如果同一个地址每次给的凭据都不一样,那这张凭据等于没有。

稳定性是很多机制生效的隐含前提,AI搜索可见性的五维度深层策略里也有同类前提。

连发两次,看凭据变不变

测法很简单:对同一个地址,间隔几秒钟连发两次普通请求,把两次拿到的ETag和Last-Modified并排比。中间没有任何人改过内容,所以理论上它们应该完全相同。

两次观测才看得出的问题,跟测试期外部扰动是同一类,测试赢了上线却掉的那二十六天值得对照。

比对项结果
两次ETag完全相同57个站
两次ETag不同16个站
两次Last-Modified不同2个站

有ETag的77个站里,16个的ETag在几秒钟内就变了,占21.9%。对这16个站来说,条件请求这套机制从一开始就不可能生效——爬虫拿着上次的凭据来问,服务端一比对发现对不上,只能返回200和全量内容。

这件事没有任何指标会报警

值得停下来想一想这个问题的性质。这16个站:有ETag、格式合法、响应正常、页面显示一切正常。任何一个只看单次响应的检查都会给它们打勾。

没有报警不等于没有问题,最佳实践清单里九条查得到出处八条数字对不上也是靠人工核对才发现的。

问题只有在把两次响应并排放的时候才会暴露,而这个动作不在任何一份标准检查清单里。需要两次观测才能发现的问题,几乎注定会被单次观测的工具全部漏掉。

为什么两次之间要留几秒

这个间隔的选择有讲究。间隔太短,可能命中同一个缓存条目,看不出问题;间隔太长,内容真有可能变了,那就分不清是随机值作祟还是真的更新了。

观测间隔属于测量设计的一部分,埋点之前先把测量框架设计清楚讲了这类前置决定的分量。

本次用的是几秒钟的间隔,理由是:几秒内一个电商首页的实质内容变化的概率极低,而缓存层的短时命中窗口通常也在这个量级之内。如果你自己测,可以试两个不同的间隔——几秒和几分钟各一次,结果一致就更放心。

Last-Modified那两个不一致的更奇怪

ETag变了还能理解,毕竟它算的是内容。最后修改时间在几秒钟内变了,那就意味着这个站在说“这份内容刚刚又改过一次”。

数字对不上往往指向连接键的问题,五个渠道加起来一百五十九个百分点是同一种反推。

本次首页这一层抓到两个,都是往回退的——第二次请求拿到的时间比第一次更早,一个退了三个小时,一个退了四分钟。这不可能是内容真的变了,只可能是两次请求落在了不同的节点上,而这些节点各自持有不同的版本。

这一条后面还会展开,因为在内页那一轮里,同类问题出现得更极端——有一个站的两次时间相差八个多小时,同样是往回退的。

节点不一致这件事的连带影响

时间倒着走这个现象,暴露的问题比条件请求本身大得多。它说明同一个地址在同一时刻,会因为落在不同节点上而返回不同版本的内容。

同一份规则在不同处理路径上行为不同,robots规则的星号对某些爬虫无效是另一个版本。

这件事的影响面很广。对用户来说,可能刷新一下页面内容就变了;对测量来说,你做的任何A/B测试都可能被这层不一致污染;对抓取来说,系统看到的这个地址是一个不稳定的东西,而不稳定的东西通常会被更谨慎地对待。

本次能看到它,纯属条件请求这套测法的副产品——因为只有连发两次并把响应头并排比,这个问题才会露头。如果只测一次,你看到的是一个完全正常的响应。

所以这条自检的价值可能超出条件请求本身:它顺带是一次很便宜的节点一致性探测。两次请求,如果拿到的凭据在格式或者时间上有系统性差异,那你的部署八成有问题。

从ETag的形状能读出什么根因?

这是本次实测最有意思的一段。把那16个站的两次ETag并排一放,成因几乎是明写在上面的。

从结构反推含义是通用手法,用SignificantLink和RelatedLink表达页面关系里的标记也是可读的。

第一类:长度段不变,哈希段在变

有五个站的ETag长这个样子:一个W斜杠前缀,然后一段十六进制数字,一个连字符,再接一段摘要。比如某个站两次拿到的分别是96c1d开头和96c1d开头,前面那段完全一样,只有后面的摘要不同。另外四个站分别是886f1、4295d、137cee、fa604开头,情况完全一致。

自动生成的字符串里藏着大量可读信息,Shopify的一百二十八种结构化数据类型怎么挑里也有靠结构判断的例子。

这种格式是很多服务端框架的默认实现:前半段是内容的字节长度,后半段是内容的哈希。那么这五个站的情况就变成了一句可以直接下结论的话——

页面的字节数一个都没多、一个都没少,内容却算出了不同的哈希。

能同时满足这两个条件的,只有一种情况:页面里嵌了一段长度固定、内容随机的字符串。最常见的就是防跨站请求的令牌、脚本安全策略里的一次性随机数、请求追踪编号、或者某个会话标识。

这个推断为什么可以直接用

因为它把排查范围从“整个页面”缩小到了“一段定长随机值”。你不需要逐行比对两次的HTML,只要去搜那几类常见的定长随机串,基本一抓一个准。

靠外部观测就能定位根因的手法很值钱,GEO投毒的三条攻击路径与三层防御也用了同一类推理。

这是一条完全靠观察响应头就能得到的诊断结论,成本是两次请求。保哥觉得这是本次实测里性价比最高的一个发现——它不需要访问服务器、不需要看代码、不需要任何权限。

第二类:整条ETag的格式都变了

另外两个站更奇怪。其中一个的两次ETag,第一次是十四个字符的短串,第二次是三十二个字符的长串。不但值变了,连长度和格式都变了。

同一站点不同版本共存会带来一堆隐性差异,网站无障碍访问怎么做的十八个改动里提过版本一致性的重要。

同一个地址,两次请求,返回了两种不同格式的ETag,最合理的解释是这两次请求被两台配置不同的节点分别处理了。可能是不同版本的服务在灰度共存,也可能是两个机房的配置漂移了。

这一类的性质跟第一类完全不同:第一类是内容里有随机值,第二类是基础设施本身不一致。修法也不一样——前者改页面,后者查部署。

第三类:缓存键相同但摘要不同

还有九个站的ETag是这样一种结构:一个固定的前缀词,一个数字编号,一个控制器名,最后是一段三十二位的摘要。两次请求里,前面三段一模一样,只有最后那段摘要在变。

缓存键与内容标识是两件事,混用会让整套机制失效,Schema聚合的五步接入方法里也有类似的键与值分不清的坑。

从结构能看出这是某套全页缓存的实现,前面几段是缓存条目的键。缓存键相同,说明系统认为这是同一个缓存条目;摘要不同,说明它每次都重新算了一遍渲染结果的哈希。

这类实现的问题在于,哈希算的是这一次渲染出来的字节,而不是这个缓存条目的身份。一个用来标识“是不是同一份内容”的东西,被拿去标识“这一次输出的字节”,两者在有随机成分的页面上永远对不上。

三类合起来的启示

形态站数根因该找谁修
长度段不变、哈希段变5页面里有定长随机值前端或模板
缓存键相同、摘要变9哈希算的是输出不是身份缓存层配置
格式和长度都变2节点配置不一致运维或部署

同一个现象三种成因三个负责人,商品页推荐位两套报表打架的那次复盘也是这种局面。

三种成因,三个不同的负责人,而它们在监控面板上的表现完全一样:什么表现都没有。

这套读法可以推广到别处

从一个字符串的结构反推它的生成方式,这个手法本身比这次的具体结论更值钱。

拼出来的字符串都能这么读,UTM链接构建器的规范与避坑清单里那套参数就是典型的拼装结构。

能这么读的前提是:这个字符串是机器按固定模板拼出来的,而模板的每一段各有含义。符合这个条件的东西比你想的多——缓存键、构建产物的文件名、追踪参数、订单编号、日志里的请求标识,都是拼出来的。

读法也有固定套路:先找哪一段变了、哪一段没变,再问“什么情况下会只有这一段变”。这个问题往往只有一两个可能的答案,因为每一段的含义把可能性框死了。

本次那五个站就是最干净的例子:长度段没变、哈希段变了,那么“内容长度不变但内容变了”这个约束,直接把答案锁死在定长随机值上。不需要看代码,不需要问人,两次请求就够了。

顺便说一个反面教训

这个手法有个前提容易被忘:你得先确认那个格式的含义,别自己脑补。

先确认含义再解释样本,品牌词和非品牌词那条线画在哪记录过一次因为记错含义而全盘推翻的过程。

本次一开始我把某个站的ETag前半段当成了时间戳,推出一个完全错误的结论,后来对着另外几个站的样本才发现那是十六进制的字节长度。五个站的前半段分别是五个不同的值,而它们的页面大小也确实各不相同——这才是能确认含义的证据。

所以正确的顺序是:先收集足够多的同格式样本,用样本之间的差异去确认每一段的含义,再拿这个含义去解释单个样本。反过来做,你会得到一个自洽但错误的故事。

第三关:真发条件请求,回不回304?

前两关都是看响应头,这一关是真的把凭据带上重发一次。

做了一半的投入最容易被忽略,共识层六信号的九十天实战指南里也点过这类半成品。

拿ETag去问

对77个有ETag的站,带上If-None-Match重发一次,结果是这样:

逐项验证比一次性判断可靠,集合页分页的索引判断与canonical设置也是一项一项过的。

返回站数比例
304未修改4862.3%
200全量重发2532.5%
301跳转45.2%

三成二的站,发了凭据却不认自己发的凭据。这个数字比前面两关都更让人意外——它们已经完成了最难的那一步,只差最后一步没做。

需要说明一下这个测法的一个边界:本次是把第一次拿到的ETag原样带回去问的。如果一个站的ETag本身就不稳定,也就是第二关没过,那它在这一关必然也过不了,两关的失败在统计上有重叠。所以第三关那25个里,有一部分其实是第二关的问题在这里再次显形。

把两关分开看仍然有意义,因为修法完全不同:第二关的问题在页面内容或者节点配置上,第三关的问题在比对逻辑上。但引用这两个数字的时候别把它们简单相加,那会把同一批站算两次。

这也是本系列反复出现的一条提醒:任何一个漏斗,都要先问相邻两级之间是不是独立的。不独立的话,累加、相乘、算转化率这些操作全都会失真,而失真的方向通常是把问题放大。

拿时间去问

对18个有Last-Modified的站,带上If-Modified-Since重发,14个返回304,占77.8%。成功率比ETag那条路还高。

精确的机制未必更稳,微软广告改UTM自动打标之后的归因影响里有类似的反直觉结果。

这个对比有点反直觉。ETag理论上更精确、更可靠,实际成功率却更低。原因在于精确本身就是负担:ETag要求内容一个字节都不能变,而时间戳只要求秒级不变。页面里那段随机令牌会毁掉ETag,却毁不掉Last-Modified。

不过这个对比要小心解读:Last-Modified的样本只有18个,而ETag有77个。十八个里成功十四个,跟七十七个里成功四十八个,前者的置信度低得多。这一条应该当成一个值得注意的方向,而不是一个可以直接引用的比例。

为什么样本这么不平衡,本身也说明了一件事:愿意给时间戳的站少得多,因为动态页面的框架往往不知道该填什么。而那些愿意填的,通常是真的想清楚了内容的更新时间从哪来——这批站本来就更用心,成功率高一点也在情理之中。

这是一个典型的选择偏差:不是这条路更好走,是走这条路的人本来就更强。看到两个成功率的时候,要先问一句“这两组样本是怎么进来的”,而不是直接比大小。

类似的陷阱在SEO数据里到处都是。比如“配了某项标记的站排名更好”,很可能只是因为愿意配那项标记的团队本来就更专业。相关不等于因果这句话人人会背,难的是每次看到数字的时候真的停下来问一句。

再补一个额外测的场景

顺手还测了一种情况:不管这个站给不给凭据,一律带上一个“一小时前”的时间去问。这相当于在说“我手上有一份一小时前的副本,还能用吗”。

多设计一个场景往往能挖出新结论,GEO到底怎么落地的实施策略里有几组类似的场景设计。

结果是142个站里只有10个返回304,占7.0%。这个数字低得符合预期——绝大多数站在这种情况下不敢说“还能用”,因为它们根本不知道自己一小时前是什么样。

这个测法的价值在于它模拟了一种真实场景:客户端手上的副本不是刚拿到的,而是放了一阵子的。能在这种情况下答得上来的站,说明它真的记录了内容的更新时间,而不只是把当前时间填了上去。那10个站,是这批样本里这件事做得最扎实的一批。

合起来看

把两条路合并,只要有任意一种条件请求能返回304就算通过:142个站里52个,36.6%。

把这个数字拆开看更清楚:四成的站没凭据,两成有凭据但凭据不稳或者不认,剩下三成六才是真正做到了。三道关卡,每一关都刷掉一批。

这个漏斗的形状值得看一眼

关卡剩下多少被刷掉的原因
起点142
第一关:有凭据8557个一个凭据都不给
第二关:凭据稳定约6916个的凭据几秒内就变了
第三关:真能回30452剩下的没做比对逻辑

漏斗形状比单个数字更有信息量,砍掉虚荣指标只盯真信号讲了怎么读这类结构。

这个漏斗有个不太常见的特点:三关的流失率相当平均,没有哪一关是绝对的瓶颈。四成、两成、一成多,一路刷下来。

大多数漏斗不是这样的,通常有一个明显的卡点,你集中解决它就能大幅提升。而这个漏斗告诉你,这件事没有捷径,三个环节各有各的成因、各归各的负责人,得一关一关过。

好消息是每一关的修复成本都不高,坏消息是你得把三关都过一遍才有结果。只做第一关,也就是开个开关生成凭据,结果可能是从没凭据变成有凭据但不被认,通过率一点没涨。

这一点在实践中很容易踩到,因为“开启ETag”是搜索这个问题最容易搜到的答案,而且做完之后你去看响应头,确实多了一行,看起来像是成功了。只有真的带着凭据重发一次,才知道有没有用。

所以自检的顺序很重要:先测终点,再往回找卡在哪一关。直接发一次条件请求,回304就全通过了,什么都不用改;不回304,再往回查是没凭据、凭据不稳、还是没做比对。这个顺序能省掉大量无谓的排查。

那52个通过的站有共同点吗

翻了一遍这份名单,最明显的共同点不是品类,也不是体量,而是它们跑在哪套基础设施上。几类现代托管平台的站几乎全数通过,而某些传统加速服务上的站通过率明显偏低。

早期的技术选型会一路影响到很多年后,建一个大站还是多个小站的取舍里算的也是这类长期账。

这个观察跟后面那一节会讲的服务器分布是一致的,而且它有个不太舒服的含义:这批站里的多数,大概率并不知道自己做到了。它们通过,是因为服务商默认就这么做;那些没通过的,也是因为服务商默认不这么做。

换句话说,这条建议在实践中的落实情况,跟“有没有人读过那份文档”关系不大,跟“选了谁家的服务”关系很大。这正是亲自型规则最讽刺的地方——一件完全由你决定的事,实际上被你多年前的一次选型决定了。

这三成六该怎么解读

先说清楚它不是什么。它不是“三成六的站做得好、六成四做得差”,因为其中有一批是主动选择不参与的,那是业务决定,不是技术缺陷。

没人考核的事最容易一直不做,把品牌当权重的四大战略里也讲过这类长期没人认领的投入。

更准确的读法是:在一条Google明确写进官方文档的建议上,能被外部验证做到的,只有三分之一出头。而这条建议既不涉及内容决策、也不涉及跨部门协调、更没有任何反向风险。

这个对比才是真正值得琢磨的:一件几乎没有阻力的事,落实率也只有三成六。阻力不在难度上,在可见性上——没人查、没人报警、没人考核,于是它就一直没被排进任何一个人的待办里。

本次三篇文章量的三样东西,落实率分别是六成五、两成二、三成六,形态各异,但成因高度一致。它们全都属于那种“不做也不会有人发现”的事。

省下来的量有多大

那52个能回304的站,全量响应平均是798.6 KB,而304响应的响应体是零字节。省掉的是接近百分之百的传输量。

带宽与计算的账要分开算才知道优化落在哪一侧,网址用扁平还是层级在SEO上到底差在哪也是一笔要拆开算的账。

当然这是单次的账。实际能省多少,取决于爬虫来的频率和你内容的变更频率。内容越稳定、被抓得越勤,省得越多;一个每天都在变的页面,这条机制本来也帮不上什么忙。

那25个不认自己凭据的站最值得说

三成二这个比例,是本次实测里最出乎意料的一个数字。这些站已经跨过了最难的一关——它们生成了ETag,说明服务器或者框架已经算过内容的哈希了。

付出成本却没拿到收益是最亏的一档,阿里国际站五百九十万页面被清零的复盘也是这种结局。

差的只是最后一步:收到If-None-Match之后,把它跟当前算出来的ETag比一下,相同就返回304。这一步在多数实现里就是几行代码或者一个配置项。

为什么会差这一步?最常见的两种情况:一是ETag由某个中间层生成,而处理请求的应用层根本不知道有这回事,也就不会去比对;二是应用层为了避免缓存问题,主动把请求里的条件头剥掉了,比对逻辑收到的是一个空值,自然永远不成立。

无论哪种,特征都是一样的:这个站在这件事上花了成本,却一分收益都没拿到。而它自己完全不知道。

那4个返回跳转的又是另一回事

还有4个站,带上条件请求之后返回了301。这说明这几个地址在带条件头的情况下走了不同的路由分支——正常请求直接返回内容,带了条件头就变成跳转。

跳转链是抓取预算里另一条明确被点名的浪费,多域名301跳转到主域名的完整配置实战里有正确写法。

这种行为本身不算错,但它很怪,因为跳转目标通常还是同一个地址。更可能的解释是某个安全或者防护层把带有不常见请求头的请求当成了可疑流量,先跳一次再说。

这一类的影响是双重的:既拿不到304,还多了一跳。而抓取预算那份文档里,恰好有另一条建议是“避免重定向链”。一条建议没做到,顺带把另一条也违反了。

首页骗了你

做到这里我本来打算收工,直到想起一件事:Googlebot每天抓的绝大多数请求不是首页,是内页。于是又跑了一轮。

首页在很多维度上都是最不具代表性的一页,首页首屏的导航主Banner到分类区怎么设计讲了它的特殊性。

换一批地址重测

从这些站自己的站点地图里,每站挑一个有一定深度的具体页面,重复完全相同的七次请求。最后拿到90个可测目标,其中89个返回200。

换一批地址结论可能完全不同,一万个电商站的网址结构实测结论也是靠大样本才站得住。

指标首页(142个)内页(89个)
有ETag54.2%73.0%
有Last-Modified12.7%6.7%
一个凭据都没有40.1%22.5%
ETag换304成功率62.3%84.6%
任一条件请求回30436.6%65.2%
两次ETag不一致21.9%4.6%

差了将近一倍

同一批站,首页只有36.6% 能回304,内页有65.2%,差1.8倍。而ETag不稳定这个问题几乎只在首页出现:首页两成二,内页不到百分之五。

不同页面类型的表现差异往往被平均值掩盖,信息词流量过大的六大危害与破局是同一类分层问题。

成因不难想。首页是全站个性化程度最高的一页:推荐位、促销条、地区提示、购物车数量、A/B分桶、会话令牌,全都挤在这一屏。每一样都会让这一次输出的字节跟上一次不同。而一个具体的商品页或者文章页,内容天然稳定得多。

还有一层原因是缓存策略的差别。首页往往被单独配置成不缓存或者短缓存,因为它承载的信息最杂、出错代价最高;而内页通常走通用规则,缓存策略更宽松,凭据也就更容易被生成和保留。首页的谨慎是有道理的,只是这份谨慎顺带把这条省钱的路也关掉了。

这个差别对怎么排查有直接影响

如果你只测了首页、发现结果很差,正确的下一步不是大动干戈改首页,而是先去测几个内页,看看差距有多大。

本次数据里这个差距是1.8倍。如果你的站也是这个量级,那么结论就很清楚:首页那一层可能确实改不动(个性化是业务需要),但内页那一层大概率只差一个开关或者一段比对逻辑。

反过来,如果你测下来首页和内页一样差,那说明问题出在更底层——大概率是整站的服务器或者加速层配置,而不是首页的个性化。同一个测法,跑两类页面,就能把问题定位到不同的层。

为什么内页样本只有90个

首页那一轮有211个域名,内页这一轮只挑出90个可测目标,差距不小,值得交代一下。

站点地图的可达性直接决定了很多流程能不能跑通,怎么实时推送搜索引擎的三种做法也依赖同一份地址清单。

原因是内页地址来自各站自己的站点地图,而不是所有站都能顺利拿到。有些站的站点地图入口找不到,有些是索引文件套索引文件、展开层数不够,还有些返回的是压缩格式或者需要特定请求头。能拿到一个可用内页地址的,就这90个。

这个筛选是有偏的:站点地图规整、可公开访问的站,技术执行力大概率更强。所以内页那一轮65.2% 的通过率,很可能是高估。真实的全样本内页通过率应该低于这个数,但仍然会明显高于首页——因为首页与内页的差别是结构性的,不会被这个偏差抹平。

把两个方向的偏差都说清楚之后,能站得住的结论就只剩一条:首页和内页有系统性差异,测的时候必须分开。至于具体差多少,本次给出的1.8倍只能当参考量级,不能当精确数字。

顺带说说怎么挑内页样本

本次是从每个站自己的站点地图里,取中间位置的一个地址。为什么取中间不取第一个?因为站点地图的开头往往是首页、分类页这类特殊页面,取中间更容易拿到一个普通的内容页。

抽样方式决定了你测到的是哪一类页面,七步GEO实战的写作流程里也强调过样本选择。

这个细节看着琐碎,但它决定了你测的到底是不是有代表性的那一类页面。如果全取第一个,测出来的可能又是一批个性化重的页面,那这一轮对照就白做了。

这条对照给出的实操结论

第一,别拿首页去判断你的站支不支持条件请求。首页是全站最不具代表性的一页,用它测出来的结论会系统性地低估你。

抓的和看的往往不是同一部分,那几张没露出来的商品图说明了这个错位。

第二,反过来也一样,只测内页会高估你。正确的做法是两边都测,然后分开看:首页那一类页面本来就难做,内页那一类才是能真正省下量的地方。

第三,如果你只有精力修一边,修内页。因为内页数量多、被抓的总次数远超首页,而且它们本来就快做到了,往往只差最后一步。

这个对照也改变了整篇文章的结论

如果只跑首页那一轮,本文的结论会是“三成六,做得很差”。加上内页那一轮之后,结论变成了“首页三成六、内页六成五,问题集中在个性化最重的那一层”。

分母怎么选决定了结论的方向,流量下降不等于SEO失败的八维度实战里有一套换分母的思路。

后一句比前一句有用得多,因为它指向了原因,也指向了动作。而这个差别,完全来自于多跑了一轮不同类型的地址。

这也是本次三篇实测里反复出现的一条方法:任何一个比例,都要问一句“这个分母是怎么选的”。换一个分母,同一批站的表现可以差出接近一倍。

内页那一轮的另外两个发现

顺带记两个数。第一,内页的Last-Modified覆盖率反而更低,只有6.7%,比首页的12.7% 少一半。这说明动态生成的内容页更不知道该怎么填这个时间,索性不填。

内容页这一层往往比首页更容易做对,Shopify图片SEO从命名到压缩的完整清单里的动作也是这样。

第二,内页里两次ETag不一致的只剩3个,而且成因跟首页那批不同——其中两个是整条格式都变了,属于节点不一致,不是页面里有随机值。换句话说,内页那一层几乎没有随机值污染的问题,剩下的都是基础设施问题。

这两条合起来给出的判断是:内页这一层,只要把比对逻辑补上,通过率很容易再往上抬一截。它的障碍是配置层面的,不是内容层面的。

那个最后修改时间,填的到底是什么?

ETag那边讲完了,回过头来看时间戳这条路。它出问题的方式完全不同,但同样隐蔽。

站点地图里那个更新时间理论上该和响应头里的是同一个值,免插件sitemap的动态优先级与分页策略讲了那个字段怎么生成。

两次请求,时间倒着走

本次抓到几个很有意思的样本。有一个站的首页,第一次请求返回的最后修改时间是当天下午两点多,第二次请求返回的却是当天上午十一点多——晚发的那次请求,拿到了一个更早的时间。

时间口径出问题会污染一整套数据,GA4默认追踪不到GEO流量的补法是另一个时间维度的坑。

另一个站的内页更夸张,两次相差八个多小时,同样是往回退的。还有几个站的两次时间相差几秒到几十秒,方向是往前走的。

两种成因

时间往回退,说明两次请求被不同的节点处理了,而这些节点各自持有不同版本的内容或者不同的时钟。这跟前面ETag格式变化那一类是同一个根因:基础设施不一致。

同一个现象要分清是内容问题还是基础设施问题,类目导航改版三轮之后仍然没写清楚用户在哪是模板层的例子。

时间往前走几秒,成因完全不同:这个站把Last-Modified写成了当前时间。也就是说,它每次响应都在说“这份内容刚刚才改过”。

后一种的后果是致命的:如果最后修改时间永远是现在,那么任何一个If-Modified-Since都不可能通过,因为客户端手上那个时间永远比“现在”早。这个站永远不会返回304,无论爬虫问多少次。

怎么一眼看出自己有没有踩这个坑

方法只有一个,也很简单:请求你的页面,看返回的最后修改时间是不是接近当前时刻。如果是,那它写的是生成时间不是修改时间,这条路是断的。

一眼能看出来的自查最容易被坚持,结构化数据怎么配合SEO落地的完整指南里也有几条这样的检查。

正确的值应该是内容真正被编辑的那个时刻——文章的最后更新时间、商品信息的最后变更时间。对静态文件来说就是文件的修改时间,服务器会自动填对;对动态页面来说,得你自己从数据里取。

顺带提醒一个容易被忽略的关联:这个时间跟站点地图里那个更新时间字段,理论上应该是同一个值。抓取预算那份文档里另有一条建议是保持站点地图更新并用好那个字段,两条建议其实指向同一份数据。

实际情况往往是两边各填各的:站点地图那边由某个插件按发布时间生成,响应头这边由服务器按文件时间生成,两个值对不上。对不上的后果是系统收到两个互相矛盾的信号,只能自己挑一个信。能对上的话,两条建议一次就都满足了。

这也是为什么动态站的Last-Modified覆盖率只有12.7%——大多数框架不知道该填什么,索性就不填了。不填至少是诚实的,填一个当前时间才是最坏的选择。

动态页面该从哪取这个时间

取值的原则是:取这个页面所依赖的所有数据里,最晚被更新的那一个时刻。

商品页依赖的数据源比想象中多,电商产品评论的结构化与GEO联动列过其中几类。

对一篇文章页,就是文章记录的更新时间。对一个商品页,要考虑的更多:商品信息、价格、库存状态、评价数量,任何一项变了这个页面的内容就变了。取它们里面最晚的那个。

对一个分类页就更复杂:它依赖的是一批商品,其中任何一个变了都算。这时候要么取这一批里最晚的更新时间,要么干脆放弃这条路,只走ETag。

这里有个很实用的取舍:如果算这个时间的成本接近于渲染整个页面,那就别算了。这条建议的目的是省资源,为了省资源反而多花一倍计算,那就本末倒置了。

一个折中办法

有个成本很低的中间方案,值得一提:给不同类型的页面定不同的粒度。

商品数据的粒度选择直接影响维护成本,跨境电商GTIN怎么申请与收录里有类似的取舍。

文章、帮助文档、政策页这类内容,更新时间是现成的,直接用。商品页取商品记录的更新时间,忽略库存这类高频变动——代价是库存变了但时间没变,客户端可能拿到旧的库存显示;如果你的库存本来就是前端异步拉的,这个代价等于零。

分类页、搜索结果页这类聚合内容,干脆不给Last-Modified,只给ETag,或者两个都不给。不是每一类页面都值得为这件事花力气,挑那些量大又稳定的做就行。

说了别缓存,又给了凭据

还有一档自相矛盾的配置值得单独说,因为它反映的是一种很典型的配置方式。

说一套做一套的地方最容易长期没人管,页脚不是杂物抽屉该怎么设计也是一个长期没人认领的区域。

35个站里有6个前后不一致

142个站里,Cache-Control中写了no-store的有35个。no-store的含义非常强硬:任何缓存都不得存储这份内容的任何部分。

两层配置各说各的是很常见的故障形态,一键退订必须写两层少一层就限流是另一个双层不一致的例子。

可是这35个站里有6个,同时还给出了ETag或者Last-Modified。一边说别存,一边给一张用来判断存着的那份还能不能用的凭据。这两句话在逻辑上是互斥的。

这种矛盾是怎么来的

几乎可以肯定不是有人这么设计的,而是两层配置叠加的结果:应用层出于安全考虑加了no-store,而Web服务器或者CDN那一层默认会给静态化的响应自动生成ETag。两边各自都对,合起来就矛盾了。

每一层单独看都对,合起来才出事,AI内容披露里那份不做什么的清单也强调了整体核对。

这类问题在多层架构里非常常见,而且往往没人发现,因为每一层单独看都符合自己的规范。只有把最终那个响应头完整打印出来通读一遍,矛盾才会显形。

矛盾的实际后果是什么

说实话,后果不算严重。规范里no-store的优先级更高,合规的客户端会遵守它,那张凭据只是被忽略了而已。

矛盾信号会让系统对你整体降低把握,实体SEO的五阶段构建方法解释了这套信心机制。

但它有两个间接代价。第一,生成ETag是有成本的——服务端算了一遍哈希,而这个哈希不会被任何人用到。纯浪费,虽然不多。第二,也是更重要的:这个矛盾是一个信号,说明这个站的响应头是几层配置叠出来的,没人通读过最终结果。

而没人通读过最终结果,通常意味着别的地方也有类似的问题——多余的头、互相冲突的指令、过期的策略。这跟上一篇里那个把sizes当探针用的思路是一样的:找那些错了也没人管的地方,它们最诚实。

怎么快速看一眼自己的响应头

方法很土:从公网请求一次你的页面,把完整的响应头打印出来,从头到尾读一遍。不是查某一个字段,是通读。

通读比单查更容易发现叠加出来的矛盾,robots.txt的虚拟与物理优先级怎么排也是一个多层叠加的例子。

通读的时候问三个问题:有没有互相矛盾的两条、有没有明显是某一层自动加上而你并不需要的、有没有该有却没有的。本次实测里的绝大多数问题,都能在这三个问题下暴露出来。

这件事一年做一次就够,前提是这一年里没换过基础设施。它的价值不在于每次都能查出问题,而在于它是唯一能看到多层叠加最终结果的方法。

顺带一个更普遍的数字

142个站里,有70个压根没有Cache-Control这个响应头。接近一半。

默认状态往往就是最终状态,自建站谷歌SEO开发期的十大优化要点里列了要主动设定的项。

没有这个头不等于不能缓存,规范里有一套默认的启发式规则,但那意味着缓存行为由各个客户端自己猜。对一个电商站来说,把缓存策略交给别人猜,不是一个好的默认状态。

各条指令的实际使用分布

把142个站的Cache-Control拆成一个个指令统计,出现频次最高的几个依次是:带具体秒数的最大存活时长、必须重新验证、不要直接使用缓存副本、不要存储、公开可缓存、私有。

保守策略在结账链路上尤其常见,结账流程改了很多轮用户回头改一次地址就全丢是同一种谨慎的代价。

值得注意的是不要直接使用缓存副本和不要存储这两条加起来的覆盖面相当大,说明相当一批电商站在首页这一层选择了保守策略。这可以理解——首页往往带着购物车状态和个性化推荐,存错一份就是事故。

但保守策略也有分寸。不要直接使用缓存副本这一条,意思是每次使用前都要向服务端确认一遍,它恰恰是最需要条件请求配合的一档:既然每次都要确认,那就该给一张能用来确认的凭据。而本次数据里,这一档里也有相当一部分什么凭据都没给。

这两条指令经常被混用

顺带澄清一个高频误解:不要存储和不要直接使用缓存副本,字面看着像,含义差得很远。

相似的配置项含义差很远,付款回来购物车就空了那两分钟宽限也是一次配置含义的误解。

前者是彻底禁止任何环节留存这份内容,用于真正敏感的页面。后者允许留存,只是每次用之前必须向服务端确认一次。后者是条件请求最理想的搭档,前者则是把这条路完全关掉。

很多站把这两条一起写上,有时候还加上一个最大存活时长为零。这样写不算错,但它表达的是最保守的那一档,也就是不要存储那一档。如果你的本意只是想每次确认一下,那就别写不要存储,你把自己的路堵死了。

爬虫换一种方法问,你的站答得上来吗?

条件请求之外,还有一层很少被提起的东西:Google的爬虫并不只发普通的取内容请求。

换一种方法问答案可能完全不同,AI推荐机制与GEO实战策略里那组对照也是靠换问法问出来的。

官方确认过的方法清单

Google的工程师提到过,他们的爬虫会发出多种HTTP方法的请求,除了最常见的取内容之外,还包括只要响应头不要内容的那种、询问一个地址支持哪些方法的那种,甚至还有写入类的方法。这份方法清单的完整讨论当时引起过不少关注,因为大多数人从没想过爬虫会发这些。

爬虫的种类和行为都在变,Google-Agent是什么以及怎么识别和应对是另一条值得跟的变化。

既然爬虫会发,那就值得测一测你的站答不答得上来。

只要响应头的那种请求

对142个站各发一次,123个返回200,占86.6%。但其中94个没有返回内容长度。

这就有点尴尬了。这类请求的全部意义就在于用极小的代价拿到关于这份内容的元信息,而内容长度恰恰是最有价值的那一项——不给长度,等于把这种请求的主要收益去掉了一大半。

没返回200的那19个里,情况五花八门:有跳转的、有直接连不上的、有返回未找到的、还有两个返回了一个表示“继续等待”的中间状态码。同一个地址,用普通方式请求好好的,换一种方式就出岔子。

其中最值得注意的是那个返回未找到的站:用普通方式请求首页返回200,用只要响应头的方式请求同一个地址返回未找到。两种方式按规范应该返回完全相同的头,包括状态码。返回不同的状态码,说明这两条路径走的不是同一套逻辑。

还有几个返回跳转的,情况类似——普通请求直接给内容,换个方法就先跳一次。这类不一致对爬虫的影响是:它拿到的元信息可能跟真实内容对不上,于是它只能放弃这条省事的路,改回全量请求。

为什么不给内容长度是个问题

94个站不给内容长度,这件事需要辩护一句:如果响应是分块传输的,规范上确实可以不给这个头,这在动态生成的页面上很常见,不算违规。

知道内容多大是很多抓取决策的前提,让内容被主动引用的五个维度里也强调过让机器省力这件事。

但站在使用者的角度,结果是一样的:你发这个请求,本来是想用最小代价知道这份内容有多大、什么时候改的、标识符是什么;拿回来一个没有大小的响应头,收益就少了一块。

要不要为此专门改造,取决于你的场景。对绝大多数电商站来说,这一项优先级很低。本文把它量出来,主要是给“爬虫会发多种方法”这个说法配一个真实的分布,而不是让你去改配置。

询问支持哪些方法的那种请求

这一项的结果最难看。142个站的返回分布是:找不到的57个、跳转的41个、方法不允许的9个、正常返回的6个,剩下是各种其它状态。

量出真实分布比照着传言改配置有用,文章标题怎么写才有人点的十个技巧里那些公式也都配了实际数据。

而按规范应该在响应里列出支持方法清单的,只有5个站。这5个给出的清单也都很朴素,基本就是取内容和取响应头两种,个别加了提交表单那一种。

这一项要不要修,答案是通常不用。它对SEO几乎没有直接影响,本文把它量出来,是为了给“爬虫会发多种方法”这个说法配一个真实的分布。知道你的站在这一项上是什么表现,比盲目照着传言去改配置有用。

不过有一个细节值得留意:返回“方法不允许”的那9个站,其实是最规范的一档。它明确告诉对方“这个方法我不支持”,而不是含糊地返回一个找不到或者跳走。规范上,返回这个状态码的时候还应该附上支持的方法清单,而那5个给出清单的站基本都属于这一档。

那些写入类的方法要不要管

官方提到的方法清单里还包括几个写入类的方法。这一项本次没有测,理由很直白:对别人的站发写入类请求是一件不合适的事,哪怕只是探测。

不需要的方法就明确拒绝,这是基本的安全卫生,品牌被仿冒抢排名的五步应对实战里也有一批同样属于卫生级别的动作。

但可以给一条常识性的建议:如果你的站不需要接受这类请求,就在服务器或者网关层明确拒绝它们。这不是为了SEO,是基本的安全卫生——一个默认接受各种方法的服务端,暴露面比必要的大。

拒绝的时候记得返回“方法不允许”并附上支持的方法清单,而不是静默丢弃或者返回一个假的成功。诚实的拒绝比含糊的沉默好,这一条在本文里已经出现第三次了。

按服务器类型看这三关的通过率

把142个站按响应头里的服务器标识分组,条件请求的通过率差异非常明显:有几类现代托管平台的通过率在八成以上,有一类知名的加速服务通过率不到四成,还有一类是零。

托管选择带来的连带影响比想象中多,外贸独立站用国内主机还是国外主机里有一份对比。

这个差异说明一件事:你的通过率很大程度上不是你决定的,是你选的那套基础设施的默认行为决定的。好消息是,这也意味着修起来往往就是一个开关;坏消息是,如果你的服务商默认不做,你多半根本不知道。

基础设施决定默认值这件事的普遍性

这已经是这三篇实测里第三次撞到同一个现象了。上一篇量图标的时候,兜底路径能不能取到图,几乎完全由“是传统服务器直接托管静态文件还是前端框架接管路由”决定;再上一篇量名字的时候,多店铺场景下名字会不会分叉,由平台的店铺配置结构决定。

不同主机档位的默认行为差别很大,共享主机VPS还是独享该怎么算这笔速度账逐档比过。

这三件事的共同点是:团队从来没做过决定,最终结果是服务商替他们做的。而服务商的默认值是按通用场景定的,不是按你的场景定的。

这条观察有一个很实用的推论:当你接手一个新站、想快速判断它的技术底子的时候,与其看它做了什么,不如看它的默认值有没有被动过。有人调整过默认值,说明有人真的看过这一层;一切都是出厂设置,说明这一层从来没进过任何人的视野。

换服务商的时候尤其要重测

顺着这条往下推:既然通过率主要由基础设施决定,那么任何一次基础设施变更,都可能悄无声息地把这件事改掉。

迁移之后要重验的项目比清单上写的多,换域名之后后台跳转登不上的三种改法记录过一次迁移事故。

换CDN、换托管平台、在前面加一层防护、把静态资源迁到对象存储——这些动作的验收清单里,通常只有“页面能打开吗、速度快不快、证书对不对”。没人会去发一次条件请求。

建议是把这一条加进迁移检查表,成本是两次请求。它跟前两篇加的那两条检查项一样,都属于“加一行、几十秒、可能省掉几年的静默损耗”那一类。

三条检查项凑成一份迁移清单

这个系列做下来,正好攒了三条可以直接加进迁移检查表的项目,都属于工具查不到、出问题不报警、修起来很便宜那一类。

清单化是对抗没人认领的唯一办法,论坛和问答结构化数据怎么做里那套字段同样需要一份清单去维护。

检查项怎么查坏了会怎样
组织名与站点名一致抠出结构化数据与og标签比对系统改用域名顶替
图标地址可用逐个请求并读文件头展示位上一个灰方块
条件请求能回304带凭据重发一次持续重复传输,无人通知

三条加起来五分钟,覆盖的是三类完全不同的失败。共同点是它们都不会让页面显示出问题,所以标准的上线验收永远抓不到。

把它们写进迁移和发版清单,是这个系列最实际的产出。不是因为这三件事本身多重要,而是因为清单是唯一能对抗“没人认领”的机制。一件事只要没被写进任何一份清单,它就只能靠某个人碰巧想起来,而人是会离职的。

这三条也可以直接给外包团队或者服务商用。它们的判据完全客观,不需要解释上下文,验收的时候一看就知道过没过。这类可验收的条目,比一堆写着“优化性能”“完善结构化数据”的模糊要求管用得多。

保哥这些年给客户写技术需求,越来越倾向于这种写法:每一条都能在五分钟内被独立验证,而且验证方式写在需求里。做不到这一点的条目,最后八成会变成一场关于“到底算不算做完了”的扯皮。

这三条恰好都符合。第一条比对几个字段是否相同,第二条看几个地址返回的是不是图片,第三条看带凭据重发回不回304。没有一条需要解释、需要判断、需要讨论。

自检和修复一共几步?

亲自型规则的落地方式很直接:没人会告诉你结果,所以你得自己建立一次观测。

把动作写成可照做的顺序比讲道理有用,PAS公式在SEO内容写作中的进阶用法也是同一种编排思路。

三分钟的自检

第一步,请求你的一个典型内页,把完整响应头打印出来,看有没有ETag或者Last-Modified。一个都没有,这条路就是断的,跳到修复第一步。

自检之后要不要上工具,二十款GEO与AEO监控工具的评测与选型可以按预算挑。

第二步,再请求一次同一个地址,把两次的凭据并排比。不一样的话,看是长度段变了还是只有哈希段变了——只有哈希段变,说明页面里有定长随机值;整条格式都变,说明你的节点配置不一致。

第三步,带上第一步拿到的凭据重发一次,看返回的是不是304。是就通过了,不是就说明服务端没有做比对逻辑。

第四步,看Last-Modified的值是不是接近当前时刻。是的话,说明它写的是生成时间,这条路等于没有。

这四步全部只需要一个能发请求并打印响应头的工具,不需要登录服务器、不需要看代码、不需要任何权限。你甚至可以拿它去测竞争对手的站——本次这批数据就是这么来的。

测竞争对手这件事顺带说两句

这套方法最有意思的一点是它完全对外可用。你能测自己的站,就能测同行的站,而且拿到的是同样精度的数据。

同行对标要挑能从外部测准的指标,品牌权威度与域名权重的区别和提升方法讨论过这类指标的可得性。

这在SEO里不常见。绝大多数技术指标要么需要后台权限,要么只能看到很粗的外部近似值。而条件请求这件事,从外面看到的和从里面看到的是同一份事实。

实用价值在哪?如果你要说服团队做这件事,一份“同行里有多少家做到了、我们排在哪一档”的数据,比任何理论都好使。本次那52个做到的站里,有不少是各自品类里的头部品牌,这个名单本身就是论据。

顺带能测出来的其它东西

同样是这几次请求,还能顺带看到不少别的信息:对方用的是哪套加速服务、页面的真实体积有多大、缓存策略保守还是激进、有没有节点不一致的迹象。

同行数据是说服团队最省力的论据,SEO汇报怎么让不同部门看到同一份事实里有现成的表达方式。

这些信息在做技术选型的时候相当有参考价值。比如你在几个托管平台之间犹豫,与其看它们的宣传页,不如去测几个跑在上面的真实站点,看默认行为长什么样。本次数据里不同服务商之间的通过率差异,从零到百分之百都有。

当然要克制。几次请求是正常访问,成千上万次就是另一回事了。做同行对标的时候,挑十几个代表性的站、每个站测一遍,足够得出结论了。

这套自检有一个前提

一定要从公网发这几次请求,不要在内网或者本机测。原因是你的响应头是好几层叠出来的:应用层、Web服务器层、加速服务层,每一层都可能加东西、改东西、删东西。

观测点放在哪决定了你看到什么,用正则从GSC里挖AI搜索提问的五步实战也是换了观测点才挖出东西。

从内网测,你看到的是某一层的输出;从公网测,你看到的才是爬虫真正收到的那份。本次那6个自相矛盾的配置,全部只有在最终响应里才看得出来——单看应用层,它写的是不要存储,完全正确;单看服务器层,它自动生成了凭据,也完全正确。

这条原则可以扩展到所有的技术SEO排查:凡是要判断“搜索引擎看到了什么”,观测点就必须放在跟它一样的位置上。这也是本文所有数据都从公网单点发起的原因。

四种失败对应四种修法

自检发现根因修法难度
一个凭据都没有服务器或框架没开开启自动生成ETag通常是一个开关
凭据每次都变、只有哈希段变页面里有定长随机值把随机值移出被哈希的部分要改模板
凭据格式都变节点配置漂移统一部署配置要查运维
有凭据但不回304没做比对逻辑在应用或网关层加比对视架构而定
最后修改时间是当前时刻填成了生成时间改成内容真实变更时间要能取到那个时间

把问题分类再排期,比一股脑全改高效,新网站SEO目标管理的三个里程碑有拆解方法。

每一类的实际改动长什么样

把四种修法再落细一点,免得看完还是不知道该跟谁说什么。

配置层的一个开关有时候比一堆内容动作更管用,GitHub Pages寄生SEO的借力实战也是靠现成能力省力气。

没有凭据这一类,去看你的Web服务器或者加速服务的配置文档,搜“实体标签”或者“自动生成校验”,绝大多数都有一个开关。开完之后立刻发一次请求确认响应头里真的多了那一行——有些服务只对静态资源生效,对动态响应不生效,光看配置看不出来。

凭据不稳这一类,先按前面那套读法判断是哪一种形状。如果是长度段不变哈希段变,去页面里找定长随机串;如果是整条格式都变,那是运维的活,跟部署一致性有关,跟页面没关系。

有凭据但不回304这一类,通常是在应用层或者网关层加一段比对:拿到请求里的条件头,跟当前算出来的凭据比,相同就返回304和一个空响应体。记得304响应里要带上凭据本身,否则客户端下一轮就不知道拿什么来问了。

时间戳填错这一类,得先确认你能不能取到内容的真实更新时间。取得到就换上;取不到,宁可不给这个头,也别给一个当前时间。这是唯一一个“不做比做错更好”的选项。

先修哪一类

按性价比排:先修“有凭据但不回304”那一类,因为它离终点最近,往往就差一段比对逻辑。再修“一个凭据都没有”那一类,因为它多半是个开关。最后才是“凭据不稳”,因为它要动页面内容,牵扯最多。

先修离终点最近的那一档,用Performance Max给零流量商品再来一次机会也是同样的优先级逻辑。

如果你的站声明了no-store且确实需要,那这套机制对首页就不适用,直接跳过,把力气放在内页上。本次数据已经说明,内页本来就是这条建议真正能省下量的地方。

修完之后怎么验收

验收方式跟自检完全一样,只是多一步:不只验你改的那个页面,验每一类页面各一个。商品页、分类页、文章页、帮助页,各挑一个跑一遍。

验收要覆盖每一类对象,五大策略让AI搜索主动推荐品牌里的落地检查也是分类做的。

为什么要分类型?因为这几类页面的数据来源、缓存策略、渲染路径往往完全不同,改好了商品页不代表分类页也好了。本次实测里首页和内页差1.8倍,就是最直接的证据。

还有一件事要验:改完之后确认内容真的变了的时候会返回200。只验304不验200,有可能改出一个永远返回304的实现,那比不做还糟——用户和爬虫都会一直看到旧内容。这个验法很简单:改一下页面内容,立刻再请求一次,看是不是200。

把它挂进哪个流程

建议挂进两个地方。一个是发布流程,每次发版之后跑一遍,成本是几秒钟。这条最重要,因为本次实测里那些节点配置不一致的问题,几乎肯定是某次发布带出来的。

把检查挂进既有流程比新建流程容易,大促与日常SEO的八维度差异与时间轴里有排期的做法。

另一个是基础设施变更流程:换CDN、加防护层、迁移托管平台的时候各跑一遍。这一条的必要性前面已经说过了——通过率主要由基础设施的默认行为决定,而默认行为会随着你换服务商而整个改变。

不建议挂成定时监控。这件事的状态很稳定,除非有人动了配置,否则它不会自己变;为一件不会自己变的事建一个每天跑的监控,只会制造噪声。

三个反直觉的判断

第一,做得最差的一关不是完全没做的那一关。四成的站没凭据,这不奇怪;奇怪的是有凭据的77个站里还有25个不认自己发的凭据——它们付出了成本却没拿到收益。

反直觉的结论往往藏在没人量的地方,被低估的九个反直觉UI设计杠杆是另一组同类观察。

第二,更精确的机制在真实环境里成功率更低。ETag比时间戳精确得多,实测成功率却低了十五个百分点,因为精确意味着更容易被一段随机字符串毁掉。

第三,这一整篇文章讲的所有问题,没有一个会触发任何报警。没有报错、没有报表、没有邮件,页面在浏览器里一切正常。这正是亲自型规则的定义——它把发现问题的责任,完整地留给了你。

三篇合起来的那条线

这是这个系列的第三篇,也是最后一篇。三篇量的是同一批国际化电商站的三样东西:名字、图标、以及服务器怎么回答“变了没有”。

平台介入方式的差别在专利文本里也有痕迹,从专利与专家访谈还原的GEO五步原理提供了另一个角度。

禁止型代劳型亲自型
本系列的样本组织名与站点名图标与站点名称的选取条件请求与304
官方措辞不被允许、可能导致偏好、支持、会考虑我们建议、请支持
核心动作删掉多余的把候选收敛到一个自己实现并自测
什么时候停过线就停候选剩一个就停不该停
怎么发现失败收到处罚通知看展示结果只能自己去问一次
本次实测的通过率17个域名有附加成分四来源一致只有22.4%首页36.6%、内页65.2%

三格的中枢是同一句话:平台给你的每一条规则背后,都藏着一个没写出来的主语——这件事到底谁动手。认错主语的代价,是把力气花在别人已经替你做完的地方,或者在别人明令禁止的地方反复试探。

如果只能记住一件事

记住那个判据:有没有一个官方工具会告诉你做到了没有。

有没有官方反馈,是判断该投多少力气的关键,Schema对AI搜索到底有没有用的官方说法与实测也是按这个判据取舍的。

有,说明平台在意这个结果,也愿意给你反馈,那就照着它的反馈做。没有,那这件事就完全是你自己的,而且很可能已经坏了很久,没有任何人打算通知你。

平台管得越松的地方,越是没人替你兜底的地方。这句话是这三篇文章唯一想说的东西。

最后留一句给做技术SEO的人

这三篇量的东西——名字、图标、条件请求——有一个共同的尴尬:它们都不在任何一份标准的SEO检查清单里。

工具查不到的清单值得自己建一份,答案引擎优化怎么让内容被优先引用里也有一批标准工具不会检查的动作。

市面上那些站点体检工具,会查标题长度、会查图片替代文本、会查内链结构、会查页面速度。没有一个会告诉你“你的服务器不认自己发的凭据”,也没有一个会告诉你“你的组织名在德国站上多了一个后缀”。

原因不难猜:工具查的是有标准答案的东西,而这三件事各有各的上下文,没法用一条通用规则判定。但没工具查,不等于没有影响;恰恰相反,正因为没人查,这些地方才会一坏好几年。

保哥的建议是给自己建一份“工具查不到的清单”,把这类东西放进去,跟着发版流程走一遍。它不会带来立竿见影的排名变化,但它是那种做完之后你不用再担心的事——而这类事情在技术SEO里,其实是最稀缺的。

这三篇量下来,最有价值的可能不是那几个百分比,而是一个很朴素的习惯:凡是官方文档里出现“我们建议”而没有配套检查工具的地方,都值得你亲自去发一次请求确认一遍。

这样的地方不多,一只手数得过来。但每一个都符合同样的特征:便宜、没风险、没人查、可能已经坏了很久。把它们一次性过完,然后写进清单,这件事的收益会一直持续到有人把清单删掉为止。

这套自检值多少钱

算一笔粗账。四步自检,加起来三分钟。修复的时间差别很大:开个开关是五分钟,补一段比对逻辑是半天到一天,把随机值移出被哈希的部分可能要动模板、需要测试。

便宜且没有反向风险的动作该优先做,把旧内容更新成AI可信来源的十二步里有一批同类动作。

收益按前面那个口径算:假设你有十万个页面被规律抓取,平均每页300 KB,其中八成的抓取碰到的是没变过的内容。做到之后,这八成的传输量归零。具体省下多少钱要看你的带宽单价,但这是一笔按月复利的账,不是一次性的。

更重要的是它的下限:做这件事几乎没有风险。它不影响用户看到的内容、不影响收录、不影响排名,最坏的情况是白做一遍。这跟很多SEO动作不一样,那些动作往往有反向风险。

唯一需要留神的反向风险是前面提过的那一条:改出一个永远返回304的实现。那样内容更新之后爬虫和客户端会一直拿到旧版本,后果比不做严重得多。所以验收的时候一定要两头都验——没变的时候回304,变了的时候回200。

这个风险的概率不高,但值得写出来,因为它是本文唯一一个“做错了比不做更糟”的地方。其余所有情况,最坏结果都只是白做一遍。

跟别的抓取预算动作比,它排第几

抓取预算那份文档里九条建议,如果按性价比排个序,这一条大概在中间偏上。

排序取决于你手上有什么资源,八家龙头怎么抢AI流量的打法拆解里也是按各自的资源禀赋排的动作顺序。

比它优先的是那几条“别让爬虫抓不该抓的东西”——合并重复内容、屏蔽无意义的参数组合、给删掉的页面返回正确状态码。那几条省的是抓取次数,这一条省的是每次抓取的字节,前者的杠杆通常更大。

但这一条有个别的建议没有的优点:它是一次性的、配置层的、不需要任何内容决策。合并重复内容要跟运营和内容团队讨论,屏蔽参数要理清业务逻辑,而支持条件请求只需要改一处技术配置。

所以合理的排法是:如果你的技术资源比内容资源宽裕,先做这一条;反过来就先做那几条。两边都做当然最好,但排序取决于你手上有什么人。

什么情况下可以直接跳过

三种情况可以放心跳过。第一,你的站页面数很少、被抓的总量本来就不大,那这笔账省不出什么。第二,你的内容确实每次都在变——比如一个实时报价页,那这套机制本来就用不上。第三,你的页面已经很小,几十KB那种,省下来的绝对量有限。

知道自己现在是什么状态本身就有价值,AI搜索时代内容优化的底层逻辑五步里第一步也是先摸清现状。

但即便是这三种情况,花三分钟测一次也不亏,因为你至少会知道自己现在是什么状态。本次实测里最让人意外的不是做不到的比例,是那些做了一半的站——它们付出了成本却没拿到收益,而且完全不知道。

常见问题解答

支持304会不会让用户看到旧内容?

不会。内容有没有变是服务端判断的,变了就返回200和新内容,一秒钟都不会延迟。304只在内容确实没变的时候返回。真正决定“客户端会不会隔一段时间才来问”的是Cache-Control这类缓存策略,那是另一件事。这两件事经常被混为一谈,分清楚之后就会发现支持条件请求几乎没有风险。

我的站不大,值得做这个吗?

收益跟规模成正比,小站省不了多少带宽。但成本也几乎是零——大多数服务器和CDN只要开一个开关。判断标准可以是:如果你的服务器成本里带宽占比不低,或者页面平均体积偏大,那就值得。本次样本里首页平均707KB,这个体积下重复传输的浪费是相当可观的。就算你判断不值得做,也建议花三分钟测一次,至少知道自己现在是什么状态。

返回304的时候,响应头还要带哪些字段?

规范要求304响应里带上那些如果返回200时也会发送、且可能影响缓存判断的头,典型的是ETag、Cache-Control、Vary这几项。不需要带内容长度,因为响应体是空的。实践中最容易出错的是漏了ETag——客户端拿到一个不带ETag的304,下一次就不知道该拿什么去问了,于是又回到全量请求。

页面里有CSRF令牌,还能支持ETag吗?

能,但要处理一下。问题的本质是这个令牌每次都不同,导致内容的哈希每次都变。有三种处理方式:把令牌从页面里挪出去,改成前端异步获取;计算哈希的时候把令牌那一段排除掉;或者干脆不用ETag,改用Last-Modified,因为时间戳对这种字节级变动不敏感。本次实测里有五个站的ETag长度段完全不变、只有哈希段在变,几乎可以断定就是这类原因。

怎么判断我的ETag是渲染前算的还是渲染后算的?

从外部很难直接看出来,但有个间接的信号:观察返回304时的响应时间。如果304的响应明显比200快很多,说明服务端在返回304之前没有走完整的渲染;如果两者差不多,说明它渲染完了才发现可以返回304,那样只省了传输没省计算。后者也不算白做,因为带宽通常仍然是大头。

ETag和Last-Modified该给哪个,还是都给?

能都给就都给,客户端会自己挑。如果只能给一个,看你的内容性质:内容会字节级变动但语义不变的(比如页面里有随机令牌),给Last-Modified更稳;内容变更时间不容易取到的,给ETag更实际。本次实测里Last-Modified的成功率反而更高,正是因为它对字节级变动不敏感。

为什么我的ETag每次请求都不一样?

最常见的原因是页面里有长度固定、内容随机的字符串,比如防跨站请求的令牌、脚本策略里的一次性随机数、请求追踪编号。判断方法很简单:连发两次请求,如果两次ETag的长度段完全相同、只有哈希段不同,那基本可以确定是这个原因。另一种可能是两次请求被不同配置的节点处理了,这种情况下连ETag的格式和长度都会变。

Search Console里能看到这一项吗?

看不到。这正是这类规则的特点:它完全发生在你的服务器上,平台只能建议,没有提供任何检查工具。抓取统计报告里能看到抓取请求的总数和响应大小的趋势,但它不会告诉你有多少次本来可以是304。唯一的检查手段是自己发一次条件请求。

用了CDN,这件事还归我管吗?

归。CDN的默认行为差异非常大,本次实测里不同服务商之间的通过率从零到百分之百都有。而且CDN那一层的配置和你的源站配置会叠加,可能出现源站说别缓存、CDN却自动生成凭据这类矛盾。正确的做法是从公网发一次请求,看最终那个响应头长什么样,而不是看某一层的配置。

拿首页测出来的结果可信吗?

不可信,而且会系统性低估。本次实测里,同一批站的首页只有36.6%能回304,内页有65.2%,差1.8倍。首页是全站个性化程度最高的一页,推荐位、促销条、购物车数量、会话令牌都在上面,这些都会让每次输出的字节不同。测的时候两边都要测,修的时候优先修内页。

最后修改时间该填什么值?

填内容真正被编辑的那个时刻:文章的最后更新时间、商品信息的最后变更时间。最坏的做法是填当前时间——那样每次响应都在说这份内容刚刚改过,任何条件请求都不可能通过。自查方法是请求一次看返回的时间是不是接近当前时刻,是的话就说明填错了。取不到真实变更时间的话,宁可不填。

爬虫真的会发那些不常见的请求方法吗?

官方确认过会发多种方法,包括只要响应头的那种和询问支持哪些方法的那种。本次实测的分布是:只要响应头那种有86.6%的站正常返回,但其中大部分不给内容长度;询问支持方法那种,按规范应该列出方法清单的只有5个站。这一项通常不需要专门去修,量出来是为了给那个说法配一个真实的分布。

声明了no-store的站怎么办?

如果确实需要no-store,那首页这一层就不适用这套机制,直接跳过。但要注意别出现自相矛盾的配置:本次142个站里35个写了no-store,其中6个同时还给了凭据,那是两层配置叠加的结果,每一层单独看都对,合起来就矛盾了。另外,no-store通常只该用在真正含个人信息的页面上,别把它套在整站上。

权威参考资料

分享到
标签
版权声明

本文标题:《304状态码能省抓取预算,142个站只有52个回得出》

本文链接:https://zhangwenbao.com/conditional-request-304-crawl-budget-audit.html

版权声明:本文原创,转载与引用请注明作者与原文链接。许可协议: CC BY 4.0

继续阅读
发表评论
分享到微信 或在下方手动填写
支持 Ctrl + Enter 提交