robots.txt 放行了整站却还是没索引:meta robots 与 noindex 误配的排查复盘
适用读者:负责官网、独立站运维与 SEO 的工程师;尤其是刚做完 CMS 改版、刚把 GPTBot / ClaudeBot / PerplexityBot 写进 robots.txt 白名单,却发现索引和 AI 引用一点没涨的人。
改版切流量的第 9 天,AI 搜索里能查到我们产品页的引用,从日均 40 多条掉到了 0。robots.txt 是我们自己一行行写的,GPTBot、ClaudeBot、PerplexityBot 全在 Allow 里,Google-Extended 也顺手放开了。运维老李在群里甩了一句:「放行都放行了,日志里爬虫一天来两百多次,怎么一条都不进索引?」
放行之后数字反而更难看
时间线不长,但每一步都踩在点上。3 月 11 日晚 22:40 切 DNS,新 CMS 接管全站;3 月 12 日补完 robots.txt,确认四个 AI 爬虫 UA 都能拿到 200;3 月 19 日上午,市场同事把引用数截图甩过来,数字是 0。

我们查了三处:Nginx access log、站点地图的覆盖率报告、搜索引擎侧的抓取统计。日志里 GPTBot 的 200 命中数没掉,改版后一周日均有 210 次左右,比改版前还高一些——爬虫来得很勤快。
反常的是「已抓取、未索引」这个桶。改版前它稳定在 1.2k 上下,改版后一周涨到 4.6k,几乎是我们全站 URL 的一半。
抓取量正常、索引量归零,这个组合基本可以把 robots.txt 排除掉,问题在页面级或响应头级的索引指令上。
两道门的机制剖析
搜索引擎处理一个 URL,是两个独立动作。抓取(crawling)负责把字节下载回来,索引(indexing)负责把内容放进检索池。
robots.txt 只在第一道门起作用,它是一份自愿遵守的抓取授权声明。RFC 9309 里写得很明白:它不表达任何关于收录的意图,Allow 不等于「请收录我」。
第二道门由索引控制(indexing directive)管着,载体只有两个:HTML <head> 里的 meta robots,以及 HTTP 响应头里的 X-Robots-Tag。爬虫解析到 noindex,就把这个 URL 从检索池里剔出去。
noindex 有个容易被忽略的读取前提:爬虫必须先把 HTML 下载下来,指令才存在。你在 robots.txt 里对这个路径写了 Disallow,爬虫就不来抓,那行 noindex 谁也读不到。
这就是最别扭的地方——你想用 noindex 把页面撤下来,却用 Disallow 把读 noindex 的路堵死了。页面会以「仅 URL 索引」的形态赖在检索池里,标题和摘要取自外链锚文本,比正常收录还难看。
放到生成式引擎优化(Generative Engine Optimization, GEO)的语境里,这事更致命。AI 搜索拼答案时用的素材来自检索池,一个被 noindex 的页面连池子都进不去,robots.txt 写得再宽松都白搭。
三条指令到底管到哪一层
| 指令载体 | 生效位置 | 谁在遵守 | 管抓取还是管索引 | 常见误用 |
|---|---|---|---|---|
| robots.txt(RFC 9309) | 站点根目录纯文本文件 | 自愿遵守的爬虫 | 只管抓取授权 | 把 Allow 当成「允许收录」 |
| meta robots | HTML <head> 内 |
抓到 HTML 之后的解析器 | 管索引与链接跟随 | 改版后旧模板的 noindex 残留 |
| X-Robots-Tag | HTTP 响应头 | 同上,但由网关层下发 | 管索引,对任何 MIME 类型都生效 | Nginx / CDN 统一加头,业务方不知情 |
| 索引快照与 site: 查询 | 搜索引擎侧 | — | 只是结果校验,不是指令 | 拿快照变化当修复成功的判据 |
顺带一句,X-Robots-Tag 在 PDF、图片这类没有 <head> 的资源上是绕不开的手段,后来我们把它单独收口管理,就是因为这类资源没法在 HTML 里声明。
排查是怎么分层的
我们把排查分成三层,从上往下剥:响应头、渲染后的 DOM、搜索引擎侧的索引快照。顺序不能反,因为越靠上层的问题越容易被下层现象盖住。
flowchart TD
A[引用数归零] --> B{curl -I 看响应头}
B -->|响应头带 noindex| C[定位 Nginx 或 CDN 层配置]
B -->|响应头干净| D[curl 取正文 grep meta robots]
C --> E[按域名拆分下发范围并 reload]
D -->|命中 noindex| F[回溯模板 include 链]
D -->|正文干净| G[抓渲染后 DOM 再比对一次]
F --> H[改成按环境变量注入]
E --> I[清空索引指令]
H --> I
I --> J[提交重新抓取并复核快照]
J --> K[观察 7 到 14 天]
有个坑要提醒:curl -sI 发的是 HEAD 请求,个别网关对 HEAD 和 GET 下发的头并不一致。我们在第二台边缘节点上就遇到过 HEAD 干净、GET 带 noindex 的情况,所以两个方法都得跑。
第一层:先看响应头
依赖与环境:curl 7.68+,在能访问线上域名的跳板机上执行,域名已做化名处理。
# 第一层:只看响应头,确认网关层有没有偷偷下发 X-Robots-Tag
curl -sI https://www.example.com/solutions/erp
HTTP/2 200
content-type: text/html; charset=utf-8
x-robots-tag: noindex, nofollow
# ↑ 这行才是元凶之一,Nginx 层统一加的,业务方压根不知道
# 换 GET 再确认一次,防止 HEAD 与 GET 的头不一致
curl -s -D - -o /dev/null https://www.example.com/solutions/erp | grep -i robots
# 命中:x-robots-tag: noindex, nofollow
# 提醒:只看首屏 HTML 不够,前端渲染注入的 meta 还要用无头浏览器再验一次
老李看到这行的时候说了句「这不是我加的吗,去年压测的时候」。翻配置历史,果然是去年 8 月为了挡压力测试流量加的,一直没人摘。
事故配置和修复后的写法对比如下,依赖与环境:Nginx 1.20+,配置托管在 Git,改完走 nginx -t && nginx -s reload。
# 事故写法:server 级统一加头,生产与预览站点共用一个配置片段
server {
listen 443 ssl;
server_name www.example.com;
# 这行会让整站所有响应都带上 noindex,PDF 和图片也跑不掉
add_header X-Robots-Tag "noindex, nofollow" always;
}
# 修复后:按域名拆分,生产域名不再下发任何索引指令
server {
listen 443 ssl;
server_name www.example.com;
# 生产环境不加 X-Robots-Tag,索引控制权交回业务模板
location / {
proxy_pass http://cms_upstream;
}
}
# 预览站单独一个 server 块,只在这里下发 noindex
server {
listen 443 ssl;
server_name preview.example.com;
# 预览站才下发 noindex,避免测试内容被搜索引擎收走
add_header X-Robots-Tag "noindex, nofollow" always;
}
改完记得验一遍真实响应头,别只看配置文件:
# 修复后 curl -sI 的响应头片段,域名已化名
HTTP/2 200
content-type: text/html; charset=utf-8
# 生产域名已无任何 X-Robots-Tag
cache-control: public, max-age=600
# 这行是边缘节点标记,与索引无关
x-cache: HIT from edge-sh-03
第二层:模板里的 meta 残留
依赖与环境:新 CMS 基于 Twig 模板,代码库本地 clone,grep 3.x。
<!-- 旧模板 legacy/public/header.html,被新 layout 直接 include 了 -->
<head>
<meta charset="utf-8">
<!-- 预览站时期为防止外网收录加的,改版时没人删 -->
<meta name="robots" content="noindex,nofollow">
<title>ERP 解决方案</title>
</head>
<!-- 修复后:按环境注入,只有预览域名才输出 noindex -->
<head>
<meta charset="utf-8">
<!-- 生产环境不输出任何 robots 指令,交由业务模板按需声明 -->
{% if env == "preview" %}
<meta name="robots" content="noindex,nofollow">
{% endif %}
<!-- 生产分支这里什么都不输出,绝不写 content="all" 之类的默认值 -->
<title>ERP 解决方案</title>
</head>
新 CMS 的 layout 里写了 include 'legacy/public/header.html',旧模板那行 noindex 就跟着进了每一个页面。我们在 13 个模板文件里 grep,命中 4 个,全是改版时图省事直接 include 的旧文件。
第三层:比对索引快照
改完之后不能当场下结论。我们做了三件事:在抓取工具里提交重新抓取、把站点地图重新推送一遍、每天记录一次索引快照数字。
判据只有一个——「已抓取、未索引」这个桶要往下掉,不是快照里那条记录消失。有些页面被剔除后,快照里还会挂着带旧标题的壳子,看那个会误判。
对做 GEO 的团队来说,排查顺序其实应该反过来:先确认页面能进索引池,再谈内容怎么被 AI 摘引用。池子进不去,后面所有优化都是空转。
noindex 和 disallow 的死结
排查到这一步,还有个更隐蔽的组合问题值得单独拆开。
| robots.txt | meta 或响应头 | 爬虫实际行为 | 索引结果 |
|---|---|---|---|
| Allow | 无 noindex | 正常抓取 | 正常索引 |
| Allow | noindex | 抓了,读到指令 | 不索引,但持续抓取,白烧抓取预算 |
| Disallow | noindex | 不来抓,指令读不到 | 仍可能以仅 URL 形态留在索引里 |
| Disallow | 无 noindex | 不来抓 | 同上,且你失去了用 noindex 撤下的能力 |
拆这个死结的顺序是固定的:先把路径临时改成 Allow,让爬虫能读到 noindex,等索引里的存量被清干净,再决定要不要恢复 Disallow。顺序反了,noindex 就是一张废纸。
stateDiagram-v2
[*] --> 抓取授权: robots.txt Allow
[*] --> 拒绝抓取: robots.txt Disallow
拒绝抓取 --> 仅URL索引: 外链或站点地图带入
拒绝抓取 --> 指令读不到: 页面从未被下载
抓取授权 --> 解析指令: 读 meta robots 与 X-Robots-Tag
解析指令 --> 剔除索引: 命中 noindex
解析指令 --> 正常索引: 无限制指令
改完之后那十四天
口径先说明白:下面是我们自己跳板机日志和抓取统计里的观测数字,不是第三方报告,样本只有一个站。
| 时间 | 抓取命中(日均) | 已抓取未索引 | AI 引用条数(日均) |
|---|---|---|---|
| 第 0 天(修完当天) | 210 | 4.6k | 0 |
| 第 3 天 | 190 | 3.1k | 3 |
| 第 7 天 | 205 | 1.4k | 17 |
| 第 14 天 | 198 | 0.9k | 34 |
回涨不是线性的,第 3 到第 7 天那一段最陡。老李的原话是「像水管里的空气排干净了」。
容易翻车的几个点
把 noindex 当成实时开关用,是最常见的一个。它是抓取时才生效的指令,下发完还得等爬虫再来一趟,急不得。
CDN 缓存会把旧响应头一起缓存住。我们改完 Nginx 配置之后,边缘节点上还挂着两天的旧头,最后是手动刷新缓存才彻底干净。
预览站模板别直接拷生产。这次事故的根因就是这个,一行 include 就够把整站干掉。
往后看,索引控制权会往两头集中:一头是 HTTP 响应头,因为 AI 爬虫对非 HTML 资源的依赖越来越高;一头是结构化数据,决定进池之后被怎么理解。GEO 这块的活,会越来越像网关配置活,而不是文案活。
我们的收口做法很土但有效:所有索引指令只允许出现在两个地方——模板里的环境变量分支,以及一份受版本控制的网关白名单;CI 里加一条 grep 门禁,生产分支出现 noindex 直接失败。
你们那边如果也踩过类似的配置坑,评论区聊聊当时的排查路径,互相省点时间。
参考与延伸
- Google 官方文档:阻断抓取与索引的区别 https://developers.google.com/search/docs/crawling-indexing/block-indexing
- RFC 9309:Robots Exclusion Protocol https://www.rfc-editor.org/rfc/rfc9309
- MDN:X-Robots-Tag 响应头 https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/X-Robots-Tag
- Google 官方文档:robots meta tag 与 X-Robots-Tag 规格 https://developers.google.com/search/docs/crawling-indexing/robots-meta-tag
GEO, AI优化AIO, 网站索引排查, meta robots, noindex, X-Robots-Tag, AI爬虫