Search Console 在一堆 URL 上报 “Indexed though blocked by robots” 或 “Excluded by ‘noindex’ tag”。仔细看,这些 URL 都在 sitemap.xml 里。sitemap 告诉 Google”请收录这个”。noindex meta 告诉 Google”请别收”。两个信号同时对一个 URL 触发,Google 的行为就不确定了——有些页被收了、有些没收,你失去了对结果的控制。这是独立站最常见的 SEO bug 之一:sitemap 和 robots meta 是两套独立流程生成的。
根因几乎都是 sitemap 生成跟 noindex 决策用的是不同的可信源。修复就是让它们共用一个。
常见原因
按命中率从高到低。
1. sitemap 拉所有路由;noindex 由模板决定
你的 build 从”所有存在的 URL”生成 sitemap。layout 按 draft: true 或分类逻辑加 noindex。sitemap 不知道 noindex 决策,就把所有都列了。
怎么判断:
# 对照 sitemap URL 与带 noindex 的页
xmllint --xpath '//*[local-name()="loc"]' sitemap.xml | grep -oP 'https://[^<]+' > /tmp/sitemap_urls.txt
while read url; do
if curl -s "$url" | grep -q 'name="robots" content="[^"]*noindex'; then
echo "CONFLICT: $url"
fi
done < /tmp/sitemap_urls.txt
有输出 = sitemap/noindex 冲突。
2. 分页页带 noindex 但在 sitemap
?page=2 起的页加了 noindex 防重复内容。sitemap 生成器把所有 URL(包括分页)都拉了。
怎么判断:sitemap 里搜 ?page=、/page/N/。出现且分页有 noindex 就冲突。
3. 作者 / 标签 / 归档页自动列入
/author/foo/(薄个人页)加了 noindex。sitemap 自动发现所有路由就把作者页加进来。
怎么判断:看 sitemap 里有没有 /author/、/tag/、/category/。跟 noindex 列表对照。
4. 草稿页不小心进了 sitemap
draft: true 的页面 layout 吐出 noindex。sitemap 生成器扫 *.mdx 没按 draft 过滤。
怎么判断:Astro 的 sitemap integration 视配置可能包含草稿。看 astro.config.mjs 的 sitemap 集成——应该 filter: (page) => !page.draft。
5. frontmatter 说发布、但模板因 bug 加了 noindex
模板里的条件错误:某个不该触发的条件触发了 noindex(比如基于缺失的字段、错误的 locale 判断)。sitemap 合理包含;模板错误 noindex。
怎么判断:手动检查任何被标记的页。对照 frontmatter 跟渲染 HTML 的 robots meta。
6. URL 已发布、后来 frontmatter 改成 draft、但 sitemap 没重新生成
你把 draft: false 改成 draft: true 撤回页面。模板吐出 noindex。sitemap 陈旧——仍列着 URL。
怎么判断:最近撤回的文章在 sitemap 里 = sitemap 陈旧。
最短修复路径
第 1 步:sitemap 和 noindex 共用单一可信源
Astro 项目,给 sitemap 配 filter:
// astro.config.mjs
import sitemap from '@astrojs/sitemap';
export default defineConfig({
integrations: [
sitemap({
filter: (page) => {
// 从文件系统或预计算 map 读 frontmatter
// 返回 false 就从 sitemap 排除
return !page.includes('/draft/') && !page.includes('/author/');
},
}),
],
});
Next.js / next-sitemap:
// next-sitemap.config.js
module.exports = {
siteUrl: 'https://yoursite.com',
exclude: ['/draft/*', '/author/*', '/api/*'],
// 或者程序化:
transform: async (config, path) => {
if (await isNoindex(path)) return null;
return { loc: path, /* ... */ };
},
};
第 2 步:审已有 sitemap 找冲突
# 拉所有 URL,逐个查 noindex
curl -s https://yoursite.com/sitemap.xml | grep -oP '<loc>\K[^<]+' | while read url; do
if curl -s "$url" | grep -q 'name="robots"[^>]*content="[^"]*noindex'; then
echo "$url"
fi
done > /tmp/conflicts.txt
wc -l /tmp/conflicts.txt
每条冲突 URL 都需要决定:保留 noindex(从 sitemap 移除)或去掉 noindex(保留在 sitemap)。
第 3 步:逐 URL 决定——收还是不收?
每个冲突问一下:
- “这个 URL 对 Google 搜索者有独特价值吗?”
- 是 → 去掉 noindex,保留在 sitemap。
- 否 → 保留 noindex,从 sitemap 移除。
分页页、空 bio 的作者页、空标签归档——通常”否”。 有内容的真实文章——通常”是”。
第 4 步:重新生成 sitemap 并重交
清理后:
npm run build # 重新生成 sitemap
curl -s https://yoursite.com/sitemap.xml | grep -c '<loc>' # 确认 URL 数
Search Console → Sitemaps → 重新提交 URL,哪怕跟之前一样。会触发重爬。
第 5 步:加 CI 校验
// scripts/check-sitemap-noindex.mjs
import fs from 'node:fs';
import { parseString } from 'xml2js';
import fetch from 'node-fetch';
const sitemap = fs.readFileSync('dist/sitemap-index.xml', 'utf8');
// 解析、逐个 fetch、查 noindex、有就失败
sitemap 里任何带 noindex 的 URL,构建失败。
第 6 步:等 Search Console 清
干净构建后,Search Console → Indexing → Pages → “Excluded” 应该 2-4 周内随 Google 重新评估而减少。
哪些情况可能不是你操作错了
Search Console 警告延迟几天。靠 view-source 在生产页面验证比报告准。报告有时显示旧数据,问题其实已经修复。
容易误判的情况
想”加强” noindex 又在 robots.txt 里 disallow。这是错的:disallow 后 Google 爬不到,看不到 noindex meta。外链可能让它无描述地被收录——更糟。
预防建议
- sitemap 从”可发布且可索引”过滤生成,不是所有路由。
- CI 校验:sitemap 中任何 URL 若页面带 noindex 就构建失败。
- 给一类页面(分页、作者、草稿)决定 noindex 时,同时更新 sitemap filter。
- 不要
robots.txt Disallow和noindex一起用——选一个。 - 每季度对照”想被收录”列表审一次 sitemap。
FAQ
- robots.txt 要 disallow noindex 页吗? 不要——Google 必须爬到才能看到 noindex。Disallow + noindex 是最常见的脚下绊。
- 能用
X-Robots-TagHTTP 头代替吗? 非 HTML 资源(PDF、图片)可以;HTML 用 meta 或 header 都等效。