Meta robots vs X-Robots-Tag——谁说了算

`<meta name="robots">` 与 `X-Robots-Tag` HTTP header 冲突时行为不可预测——怎么选、怎么保持一致。

你在 staging 页上加了 <meta name="robots" content="noindex">,一周后发现生产环境的同一页从 Google 消失了。或者反过来:你在感谢页 meta 里写了 noindex,但它还在搜索结果里。两种情况的根源都是同一个——Google 通过两条通道读取 robots 指令,两条不必一致。HTTP 响应头 X-Robots-Tag 是另一条通道;当两者不一致时,Google 不会选一个作权威,而是合并取最严格的值。

也就是说,CDN 规则里一条不起眼的 X-Robots-Tag: noindex 可以静默杀掉一个 meta 里写着 index 的 HTML 页面。View Source 看不出问题,只有 curl -I 能看到真相。

先判断你属于哪种情况

情况 1:meta 里有 noindex,但页面仍被收录

怎么发现:

curl -s https://yourdomain.com/path | grep -i 'name="robots"'
# 输出:<meta name="robots" content="noindex">

curl -sI https://yourdomain.com/path | grep -i x-robots
# 输出:(什么都没有)—— meta 说 noindex,header 什么也没说

然后 Search Console 的 URL 检查里这一页显示已被收录。

原因:自从你加 meta 之后 Google 还没有重新抓取,或者 meta 是用 JavaScript 渲染的、本次抓取里 Googlebot 没执行 JS。header 是每次请求都会读到的;meta 要等重抓 + 渲染才能生效。

修复:把 noindex 渲染进 SSR 的初始 HTML(不要靠客户端 JS),然后用 URL 检查里的”测试实际网址”确认 Google 在渲染 HTML 里看到了 noindex,再点”申请编入索引”触发重抓。完整移除时间线见 设了 noindex 但页面还在搜索结果里

情况 2:meta 没有 noindex,但页面却从索引消失

怎么发现:

curl -sI https://yourdomain.com/path | grep -i x-robots
# X-Robots-Tag: noindex, nofollow

浏览器打开页面、查看源代码——没有 robots meta,或者写的是 index, follow。罪魁就是这个 header。

原因:典型泄漏路径:

  • Vercel、Netlify、Cloudflare Pages 的预览部署会给 preview 域名注入 X-Robots-Tag: noindex,但生产别名配置错了也命中了。
  • WAF 或 CDN 规则原本只想覆盖 *.staging.example.com,但 host 模式同时匹配到了你的主域名。
  • 源站中间件根据 NODE_ENV !== "production" 加上 X-Robots-Tag: noindex,结果生产环境没设这个 env,规则照样生效。

修复:定位哪一层注入了 header。一层一层往回找:

# 直连源站(绕过 CDN)
curl -sI --resolve yourdomain.com:443:ORIGIN_IP https://yourdomain.com/path | grep -i x-robots
# 再走 CDN
curl -sI https://yourdomain.com/path | grep -i x-robots

源站干净、CDN 脏 → CDN 规则;两者都脏 → 源站/应用层。

情况 3:PDF、图片或其他非 HTML 资源从搜索消失

怎么发现:

curl -sI https://yourdomain.com/whitepaper.pdf | grep -i x-robots

PDF、图片、其他非 HTML 响应无法承载 <meta> 标签。对它们而言,Google 唯一能读到的 robots 信号就是 X-Robots-Tag。如果托管平台或框架把 X-Robots-Tag: noindex 作为静态资源的默认值,你的 PDF 永远无法被收录。

原因:某些框架(Next.js 的默认 header、S3+CloudFront 配了默认 noindex 策略)会给所有响应、包括静态资源都加 X-Robots-Tag

修复:把 noindex 规则限定到 HTML 页面或具体路径,而不是全站默认。

情况 4:表现飘忽——有时被收录有时没被

怎么发现:URL 检查显示渲染后的 HTML 带 noindex,但原始响应(“HTTP 响应”那一栏)没有。或者反过来。

原因:JavaScript 在页面加载后修改 meta。本次抓取 Googlebot 执行了 JS 就看到 noindex;没执行就看到原始的 index 值。header 通道始终被读取;meta 通道依赖渲染。

修复:不要用客户端 JS 切换 robots meta。在 SSR HTML 里就把最终值渲染出来,或者用服务端的 X-Robots-Tag

情况 5:两边都写了 noindex,页面还在被收录

怎么发现:

# 两个信号都在
curl -s https://yourdomain.com/path | grep -i robots  # meta 写了 noindex
curl -sI https://yourdomain.com/path | grep -i x-robots  # X-Robots-Tag: noindex

# 但是:
curl -s https://yourdomain.com/robots.txt | grep -i path
# Disallow: /path

原因:robots.txt Disallow 把抓取整个挡住了。Google 永远不去取这一页,永远看不到 meta 或 header,仅凭外链信号继续把 URL 留在索引里(就是那个著名的”虽被 robots.txt 屏蔽,但仍被收录”状态)。这是 noindex 失败最常见的形态。

修复:删掉 Disallow 那一行。URL 必须可抓取,Google 才能看到 noindex 并完成移除。

Google 怎么解决冲突

按 Google 文档:

  • meta robots 和 X-Robots-Tag 都是有效信号。
  • 两者同时存在时,按指令逐项取最严格的值。
  • noindexindexnofollowfollownoarchive 胜 缺省。
  • 如果 robots.txt 屏蔽了 URL,两个信号都读不到——URL 还可能以无摘要的形式留在结果里。

所以 meta 和 header 之间不存在”谁赢”,是合并。实操原则:生产环境里绝不让它们打架。

最短修复路径

按命中率排序:

  1. 对问题 URL 跑 curl -I → 60% 的情况下 header 就是凶手。View Source 里的 meta 会让你忽视真正原因。
  2. robots.txt → 25% 的情况下是 Disallow 让 Google 永远看不到你设的信号。
  3. 逐层排查请求链路 → 源站 header 正确但边缘错了,就是 CDN / WAF / 托管平台的规则。
  4. 把 robots meta 写到 SSR,别靠 JS → 剩下的边缘情况几乎都是”JS 设了 meta 但 Googlebot 这次没跑 JS”。

一个安全的生产配置

按内容类型分工。下面这套覆盖绝大多数站:

  • HTML 页面:robots meta 写进 SSR HTML。HTML 响应不要再加 X-Robots-Tag,除非有特殊理由。
  • PDF、图片、下载文件:用 X-Robots-Tag header(meta 用不了)。
  • Staging 域名X-Robots-Tag: noindex 严格限定在 staging 主机名上。

示例:把 staging 的 noindex 限定到主机名,而不是全局。

# Nginx——只在 staging
server {
  server_name staging.yourdomain.com;
  add_header X-Robots-Tag "noindex, nofollow" always;
}

server {
  server_name yourdomain.com;
  # 这里不加 X-Robots-Tag。每页的 noindex 走 meta。
}

预防建议

  • 按文件类型记录哪个信号 canonical,写进仓库里的 SEO README。
  • CI 加一条检查:对生产 URL 抽样跑 curl -I,意外出现 X-Robots-Tag 就让构建失败。
  • 同一 URL 绝不同时 meta noindex + robots.txt Disallow——Google 永远看不到 noindex。
  • 不要用客户端 JS 切换 robots meta——Googlebot 本次可能跳过 JS。
  • 改完 Vercel / Netlify / Cloudflare 设置后,立刻对若干页面跑 curl -I 验证 header 没有意外变化。

FAQ

Q:meta 里设了 noindex 但页面还在 Google。先查什么? A:先跑 curl -sI https://yourdomain.com/path | grep -i x-robots。如果没 header,再看 robots.txt 是不是对这个路径写了 Disallow。这两步能解决约 85% 的情况。都不是的话,几乎都是”Google 还没重抓”——等,或者用 URL 检查里的”申请编入索引”。

Q:同一页能同时用 meta 和 X-Robots-Tag 吗? A:能,但必须一致。Google 按最严格的指令合并。meta 写 index、header 写 noindex,最终结果是 noindex。HTML 上同时写两个是冗余,选一个就好。

Q:X-Robots-Tag 能用在 HTML 上吗? A:能,效果和 meta 完全一致。只是不那么常见,因为大多数 CMS 会替你写 meta。X-Robots-Tag 是非 HTML(PDF、图片、ZIP)等无处写 meta 的场景的正确选择。

Q:staging 把 noindex 泄漏到了生产,怎么最快撤销? A:先把 header 移掉(部署或改 CDN 规则),再去 Search Console:对受影响 URL 做 URL 检查 → “测试实际网址” → 确认 header 已消失 → “申请编入索引”。首页或顶层页通常 24–72 小时就能重新收录。

Q:nosnippetmax-snippet 在 meta 和 header 之间的合并规则一样吗? A:一样——同样取最严格的值。meta 写 max-snippet:50、header 写 max-snippet:200,最终生效的是 50。

相关阅读

标签: #SEO #排查 #排查 #结构化数据 #robots.txt #X-Robots-Tag