robots.txt 不生效:3 个原因 + 修复路径

改了 robots.txt 但 Google 还在爬同一批 URL。常见原因:CDN 缓存 robots.txt 几小时;静态和动态两份 robots.txt 同时存在,静态优先;Google 还没重新拉。先做:确认 robots.txt 只有一个来源。

你在 public/robots.txtsrc/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-cacheHIT 就是缓存命中。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 应当是 MISSDYNAMIC(因为带了 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 等待

相关阅读

标签: #部署 / 托管 #排查 #排查 #SEO