你在 public/robots.txt 或 src/pages/robots.txt.ts 里加了一条 Disallow: /admin/,部署后 Search Console → robots.txt 报告看到的还是上一版本,Googlebot 也在继续抓 /admin/。这通常不是 robots.txt 语法错——而是 Google 缓存 robots.txt 最长 24 小时、CDN 又叠了一层缓存、或者你的项目里其实有两份 robots.txt 互相覆盖。
本文按命中率拆开 5 类原因,每类都给一条可以直接 curl 或在 Search Console 里验证的判断方式。
常见原因
按命中率从高到低:
1. Google 的 robots.txt 缓存还没过期
Google 官方文档明确说会缓存 robots.txt 最长 24 小时(robots.txt FAQ)。你刚改完,Googlebot 用的还是缓存里那一份。
如何判断:Search Console → 设置 → robots.txt 报告,看 “Last fetched” 时间。如果是几小时前抓的、内容是旧版,就是缓存。
2. CDN 给 robots.txt 加了 edge cache
Cloudflare / Vercel Edge 默认对 .txt 文件按 Cache-Control 头缓存,常见 4 小时甚至 24 小时。你 push 完新版本,源站对,但 Googlebot 拉到的还是 CDN 边缘的旧版。
如何判断:
curl -I "https://yourdomain.com/robots.txt"
看响应头里 cf-cache-status / x-vercel-cache:HIT 就是缓存命中。age 字段告诉你这份缓存已经多久了。
3. 同时存在两份 robots.txt,静态优先
最坑的一种:你在 Astro / Next 里写了动态路由 src/pages/robots.txt.ts 生成 robots,但 public/robots.txt 里还有一份历史文件没删。绝大多数框架对 public/ 里的静态文件优先输出,动态路由被覆盖。
如何判断:
ls public/robots.txt src/pages/robots.txt* 2>/dev/null
如果两个都存在,问题就是它。
4. 用 Disallow 想达到 noindex 的效果
Disallow: /private/ 只是阻止抓取,不阻止索引。如果别处有外链指向那个 URL,Google 仍然可能收录(标题显示 “No information is available for this page”)。你以为 robots.txt 失败了,其实它做了它该做的——只是你需要的是另一个工具。
如何判断:在 Search Console → URL 检查器输入该 URL,看 “Indexing allowed?” 和 “Crawling allowed?” 两栏。如果显示已索引但禁止抓取,说明 robots 生效了,问题在你需要 noindex。
5. 大小写 / 字段名错
disallow: 必须是 Disallow:(首字母大写)。User-agent: 不能写成 User-Agents:。Wildcards 必须放对位置——Disallow: */admin/ 在某些 bot 上不受支持。
如何判断:用 Search Console → robots.txt 测试工具粘贴你的内容,它会标出 syntax errors。
最短修复路径
按收益从高到低,前 3 步通常就能解决 80% 的问题。
Step 1:用 curl + cache buster 拿到真正的源站响应
curl -I "https://yourdomain.com/robots.txt?cb=$(date +%s)"
curl -s "https://yourdomain.com/robots.txt?cb=$(date +%s)"
第一条看响应头,第二条看内容。判断点:
- 状态码必须 200(不是 301 / 404)
content-type: text/plain或类似(不能是text/html——会被 Google 当 HTML 忽略)cf-cache-status/x-vercel-cache应当是MISS或DYNAMIC(因为带了 buster)- 内容是你最新版本
如果带 buster 是新版、不带是旧版 → 缓存问题,走 Step 2。如果带 buster 也是旧版 → 部署没成功,走 Step 3。
Step 2:针对 /robots.txt 单条清 CDN
不要 purge everything。
- Cloudflare:Caching → Configuration → Purge Custom URLs,粘
https://yourdomain.com/robots.txt - Vercel:项目根目录跑
vercel --prod --force,或在 dashboard 重新触发部署 - Netlify:Deploys → Trigger deploy → Clear cache and deploy site
清完再用 Step 1 不带 buster 的 curl 验证响应头变成 MISS、内容更新。
Step 3:确保只有一个 robots.txt 来源
# 删掉 public/robots.txt,只保留动态路由(或反过来)
rm public/robots.txt
# 或:删掉动态路由
rm src/pages/robots.txt.ts
二选一。然后重新 build + 部署:
npm run build
ls dist/robots.txt && head -20 dist/robots.txt
确认 dist/robots.txt 是你想要的那份。
Step 4:让 Google 立刻重抓
到 Search Console → 设置 → robots.txt 报告 → “Request a recrawl”。点完通常 1-2 小时内 “Last fetched” 时间会更新。
如果你想完全去索引(不只是禁止抓取),别在 robots.txt 里 disallow,改用 page 上的 meta:
<meta name="robots" content="noindex">
或者在 HTTP 响应头里:
X-Robots-Tag: noindex
robots.txt 的 Disallow 实际上会阻碍 Google 看到 noindex 标签,所以两者用法相反。
预防建议
- 把 robots.txt 的”来源”写进 README,团队所有人知道是
public/还是动态路由 - 改 robots.txt 后先用 Search Console 的测试工具贴一遍,再部署
- 想去索引就用 noindex meta / X-Robots-Tag header,不要用 Disallow
- 部署后跑
curl -I /robots.txt冒烟测试,断言 200 + text/plain + 最新内容 - 给 robots.txt 设较短的 Cache-Control(如
max-age=600),减少 CDN 等待