本文是一次真实排查记录:站点在 Google Search Console 里显示大量页面“未编入索引(Not indexed)”,通过逐条定位,最终锁定并修复了 4 类问题。适合用静态生成(SSG)+ CDN 部署的站点参考。

一、先看懂 GSC 的“未收录”分类

打开 Search Console 的“网页 → 未编入索引”,Google 会按原因分组。常见的几类,性质完全不同:

原因 含义 要不要处理
Page with redirect 该 URL 有重定向 一般正常(如 http→https)
Alternate page with proper canonical tag 被判为“别的页面的替代页” 要查 canonical 是否指对
Crawled - currently not indexed 抓了但暂未收录 内容页要关注;sitemap.xml 属正常
Duplicate / Soft 404 重复或软 404 要处理

关键心态:GSC 里的“示例 URL”是历史抓取快照(看 last crawled 日期),不代表页面当前状态。判断线上真实情况,一律以 curl 实测为准。

二、问题 1:canonical 全部指向首页

症状

每个详情页的 <head> 里 canonical 都写成了首页:

<link rel="canonical" href="https://example.com/">

后果非常严重:Google 认为所有页面都自称是首页的副本,于是只保留首页、其余全部当“替代页”丢弃,收录数几乎归零。

排查

直接抓线上 HTML 看 ground truth:

curl -s https://example.com/some/page.html | grep -o 'rel="canonical" href="[^"]*"'

如果每个页面都输出首页地址,就是 canonical 生成逻辑坏了(或部署的是旧文件)。

修复

每个页面的 canonical 必须指向它自己的绝对 URL

<!-- 章节页 -->
<link rel="canonical" href="https://example.com/n/book/001.html">
<!-- 分类页 -->
<link rel="canonical" href="https://example.com/c/beauty/">

模板里用“页面自身路径”生成,别用默认值兜底成 /。改完记得重新生成 + 重新部署——很多时候代码早修好了,只是线上跑的是旧静态文件。

三、问题 2:www 与非 www 重复内容

如果 https://example.com/https://www.example.com/ 都返回 200(都能访问),就是重复内容。应当二选一为主,另一个 301 跳过去

验证是否已跳转:

curl -s -o /dev/null -w "%{http_code} %{redirect_url}\n" https://example.com/

用 Cloudflare 的话,加一条重定向规则(或页面规则)把非 www 打到 www:

  • 匹配 URL:example.com/*
  • 转发到:https://www.example.com/$1,状态码 301

四、问题 3(最隐蔽):软 404 —— 不存在的路径返回“200 + 首页”

症状

随便访问一个根本不存在的路径,却返回了首页内容、且状态码是 200:

curl -s -o /dev/null -w "%{http_code}\n" https://www.example.com/this-path-not-exist-xyz/
# 期望 404,实际却是 200

这就是软 404(soft 404)。很多 SSG + Cloudflare Pages / SPA 部署会默认对“找不到的资源”回退到 index.html 并返回 200。后果:

  • 任何打错的、过期下架的 URL 都变成“200 + 首页内容”;
  • Google 认为你有无数个跟首页重复的页面 → 判为“首页的替代页 / soft 404” → 浪费抓取预算、稀释收录。

这往往是“大量页面未收录”的真正大头,比 canonical 更隐蔽。

修复:让不存在的路径返回真正的 404

Cloudflare 的静态资源服务由 not_found_handling 控制:

  • single-page-application:找不到就返回 200 + index.html(SPA 才需要);
  • 404-page:找不到就返回最近的 404.html + 真正的 404 状态码

对内容站/静态站,做法是在输出目录放一个 404.html。Cloudflare Pages 检测到它后,会对未命中的路径返回该页 + 404 状态码。404 页记得加 noindex

<meta name="robots" content="noindex,follow">

修完再测一次,乱打路径应返回 HTTP 404

五、问题 4:静态生成要清理“幽灵页面”

增量生成通常只覆盖/新增,不会删除已下架内容对应的旧 HTML。这些旧文件继续被部署,就成了“幽灵页面”。

建议:全量生成前先清空该站点的输出目录再重建,保证下架的内容能真正从站点消失(清空时务必做路径安全校验,只允许删“输出目录/域名”这一层,避免误删)。

六、关于 sitemap.xml 的正确认知

两个常见误解:

  1. sitemap.xml 出现在“Crawled - currently not indexed”是正常的。它是给爬虫读的数据文件,本就不该作为网页被收录,会一直停在这个状态,不是错误。
  2. sitemap 里应当只列真实存在、可收录的页面,且用绝对 URL、带 lastmod。下架的内容要从 sitemap 移除。

改完后在 GSC 重新提交 sitemap,并对想收录的页面用“网址检查 → 请求编入索引”。

七、排查清单(收藏备用)

  1. curl 抓线上 HTML,核对每页 canonical 是否自指
  2. 确认 www/非 www 只有一个主版本,另一个 301
  3. 访问一个不存在路径,确认返回 404 而非 200+首页;
  4. 全量重建时清空旧产物,杜绝幽灵页;
  5. sitemap 只列真实页面,GSC 重新提交;
  6. 记住:GSC 数据有滞后,改完通常几天到两周才更新,耐心等重爬

小结:静态站 SEO 的坑大多不在“写了什么”,而在“部署出去的到底是什么”。养成用 curl 验证线上真实响应(状态码 + canonical)的习惯,能省下大量猜测时间。