< BACK 无头CMS SEO:SSR何时有害及如何修复 -- 线条艺术插图

无头 CMS SEO:当 SSR 反而伤害排名时,以及如何修复

2021 年,一个客户给我打来电话,慌张得很。他们用 Contentful 无头架构和 Next.js 前端重新发布了电商产品目录,4,200 个产品页面。他们的代理商给他们兜售的说法是:现代技术栈,速度快如闪电,Google 会喜欢它。上线六周后,自然流量下降了 61%。不是爬虫错误。不是人工惩罚。就是……消失了。

关键点:使用无头架构默认不会改善SEO:爬取中断来自客户端渲染、元数据传输缺失,以及预览URL泄漏到索引中。

我现在看过这种模式太多次了。最令人沮丧的部分?SSR 在技术上是工作的。页面在服务器上渲染。HTML 被返回了。但有大约七个其他地方整个系统在悄悄瓦解,而没人想过去检查。

这篇文章不是在讨论无头架构好还是不好,它显然可以非常出色。这是关于 SSR 在无头架构上针对 SEO 的具体、可解决的失败方式,以及你实际应该怎么做。

---

SSR 自动修复无头 SEO 的迷思

问题是这样的。当客户端渲染在 2016-2018 年左右成为主流时,SEO 社区集体陷入了恐慌(理由充分)。Google 爬虫对 JavaScript 执行的处理不一致,内容无法被索引,单页应用网站排名下滑。所以业界猛烈转向 SSR 作为解决方案。

它确实比纯 CSR 更好。但"更好"不等于"完全解决"。

SSR 解决了渲染问题。但在缓存策略、爬虫预算、canonical 混乱,或者 CMS 和 HTML <head> 之间的元数据管道方面,它几乎没有作用。这些是完全独立的失败模式。在无头架构中,每一个都至少涉及两个系统——CMS 和前端框架——需要达成一致。

它们通常做不到。

---

SSR 在无头堆栈中实际破坏 SEO 的地方

首字节时间问题

SSR 只有在你的服务器足够快的情况下才会快。在无头设置中,你的 Next.js 或 Nuxt 服务器必须从 CMS API 获取内容才能响应。如果 Contentful(或 Sanity、Storyblok 或其他任何一个)出现缓慢时刻,你的 TTFB 就会飙升。我见过在配置不当的 SSR 设置中,CMS API 冷启动期间 TTFB 飙升超过 3 秒。

Google 使用 TTFB 作为抓取调度的信号。响应缓慢意味着 Googlebot 每个会话抓取的页面更少。在大型目录站点上,这直接导致页面在抓取队列中卡住数周。

在运行时生成的规范标签

这个通常会让人措手不及。在 WordPress 这样的传统 CMS 中,canonical 标签被烤进主题或 SEO 插件里。在无头架构中,你的 canonical 逻辑存在于前端代码中,可能在 Next.js 的 <Head> 组件里,可能在布局包装器中。CMS 完全不知道你在渲染什么 canonical。

那么当产品 URL 有用于排序或过滤的查询参数时会发生什么?或者当你的 CMS 返回的页面 slug 与你的路由逻辑略有不同时呢?你会得到 canonical 标签要么指向错误的 URL,要么根本不存在。我去年在一个 Seahawk 项目中为一家英国零售商发现了这个问题,800 个页面都被 canonical 到 /?page=1,因为分页逻辑传递了错误的 prop 给 SEO 组件。花了两天才找到。三行代码就修复了。

无后备方案的元数据管道

每个无头 CMS 都允许你添加 SEO 元数据字段、meta 标题、描述、OG 标签。很好。但当编辑发布页面后忘记填写这些字段时会发生什么?在装有 Yoast 的 WordPress 中,你会得到一个生成的备用方案。在无头架构中,如果你的前端组件没有明确的备用逻辑,你会得到一个空的 <title> 标签。或者更糟的是,原始字段名被回显到了 HTML 中。

始终显式构建后备链:seoTitle ?? pageTitle ?? siteName。每个字段。无一例外。

这是模式驱动型 CMS 大显身手的地方。在 Sanity 中,SEO 字段(元标题、规范链接、hreflang、结构化数据)是内容模型的类型化属性,而不是事后粘贴到页面编辑器上的框。回退链在模式中只需定义一次,而不是在每个前端组件中重新实现,GROQ 查询返回模板所需的精确字段,没有过度获取,也不需要解析松散的 CMS 响应。元数据管道变得更可靠,因为信息源是内容模型,而不是消费它的代码。我最近为一个客户发布了这个方案,它消除了本节所讨论的整个运行时错误类别。

---

没人深入思考的缓存层

Next.js 中的 ISR(增量静态再生成)确实很聪明。你获得了大多数情况下的静态性能,同时又能够按计划重新验证。但对 SEO 来说,重新验证窗口是一个影响重大的决策。

设置 revalidate: 3600(一小时),你的内容编辑在发布后最多一小时内都不会被 Googlebot 看到。对于博客来说没问题。但对于新闻网站或电商闪购页面来说,这就是灾难。我有一个客户进行了一场 4 小时的限时促销,其中 45 分钟里页面一直显示缓存的"已售罄"状态,因为在规划折扣活动时没人考虑过 ISR 时间窗口。

修复方案不总是"更积极地重新验证"。更频繁的重新验证意味着更多的源站负载。真正的修复是按需重新验证,在内容发布时从你的 CMS webhook 触发缓存清除。Next.js 自 v12.2 以来就支持按需 ISR。Contentful、Sanity 和 Storyblok 都支持出站 webhook。把它们连接起来。大约需要一个下午。

---

爬虫预算与无头 URL 表面积

传统 CMS 平台在 URL、分类、分页、archive 的 canonical 处理等方面有多年的惯例。无头架构给你完全的自由,这意味着你必须自己用代码做出所有这些决策。

当你不够谨慎时,自由是危险的。

一个带有分面筛选的无头产品目录很容易生成数十万个独特的 URL,比如 /products?colour=red&size=M&sort=price-asc 及其所有排列组合。如果你的 SSR 层用唯一的 HTML 渲染所有这些 URL,而没有规范标签指向基础 URL,那你就给 Googlebot 设置了一个无限迷宫。

在每个无头项目中我都会做的几件事:

  • 在 robots.txt 中阻止所有不具 SEO 意义的查询参数 URL
  • 在所有过滤/排序变体上实现单个规范链接,指向简洁的基础 URL
  • 在小型网站的第 2 页之后的分页页面上使用 <meta name="robots" content="noindex, follow">
  • 根据 Google Search Console 的覆盖率报告审核 XML 网站地图,对比 Googlebot 实际爬取的内容。首次审核时,这两者很少一致。

请从你的 CMS 动态生成网站地图,而不是在构建时静态生成。只反映最后一次部署内容的网站地图,如果编辑在两次部署之间发布了 40 个新页面,就毫无用处。

---

结构化数据缺口

无头 CMS 在结构化内容方面表现出色。Schemas、字段类型、引用,Sanity 和 Contentful 的数据建模都很漂亮。但用于 SEO 的结构化数据(JSON-LD schemas、Product、Article、BreadcrumbList 等)是另一回事。

我审计过的大多数 headless 前端项目要么完全没有 JSON-LD,要么只是在布局中附加了一个通用的 WebSite schema。这是一个失误。在产品页面上,你需要 Product schema,包括从 CMS 实时提取的价格、库存和评价数据。在食谱或操作指南页面上,恰当的 schema 可以直接影响 Google 中的富媒体搜索结果。

实现并不复杂。在 Next.js 中,将你的 JSON-LD 放入 <Head> 内的 <script type="application/ld+json"> 标签中,从页面 props 填充数据,然后在 Google 的富媒体搜索结果测试工具中测试。复杂的是确保你的 CMS 内容模型为前端提供正确的字段。这是一个内容架构讨论,不是开发工作单。

---

端到端修复元数据管道

让我给你一份我在每次 headless SEO 审计中都会用到的清单。不是概念性的。是实际的步骤。

  1. 验证渲染的 HTML,使用 curl -A "Googlebot" [your URL] 并检查原始响应。<head> 标签实际包含什么?不是你的浏览器在水合后显示的内容,而是原始的服务器响应。
  2. 在 20 个随机页面上检查规范标签准确性,尤其是带有参数的产品/分类页面。如果网站很大,可以用 node-fetch 编写一个小脚本,大规模拉取和解析规范标签。
  3. 从三个位置测试 TTFB,我使用 WebPageTest,以 Googlebot UA 从伦敦、法兰克福和弗吉尼亚进行测试。如果任何位置的 TTFB 一直超过 800ms,那么在做其他事情之前,先深入调查你的 CMS API 响应时间。
  4. 根据 GSC 审核你的网站地图,从 Search Console 导出覆盖率报告。将网站地图中的"有效"URL 与实际情况比较。任何在网站地图中显示"已排除"的 URL 都需要调查。
  5. 检查重复的 `<title>` 和 `<meta description>` 标签,当布局组件和页面级组件都试图写入元数据时,这种情况比你想的要常见。
  6. 端到端测试按需重新验证,在你的 CMS 中发布一个内容变更。多久后它会出现在服务器渲染的页面上?如果测量时间以小时计,那么就需要设置 webhook。
  7. 在代表性页面类型上验证结构化数据,至少包括Product、Article、FAQ。使用Google的Rich Results Test在实时URL上进行测试,而不仅仅是本地测试。

---

我实际使用的工具

不是理论列表。这是我处于 headless SEO 修复中间时,我电脑上打开的东西。

  • Screaming Frog,以渲染模式抓取实时网站以查看Googlebot看到的内容。首先将渲染模式设置为"None"以查看原始SSR输出,然后与"JavaScript"模式进行比较。
  • WebPageTest,TTFB、服务器响应瀑布流、CDN边缘命中/未命中头部。
  • Google Search Console,覆盖范围报告、特定页面的URL检查、按页面类型划分的Core Web Vitals。
  • Postman或`curl`,用于手动查询CMS API以检查实际返回到SSR层的数据。
  • Next.js内置日志,经常被忽视。在分阶段审计期间打开详细日志将准确显示你的渲染在哪里等待。

说实话,我发现的 80% 的 headless SEO 问题,仅从 Screaming Frog 就能看出来,只要你知道要找什么。

---

常见问题

Next.js 搭配 SSR 能保证良好的 SEO 吗?

不是。SSR意味着你的HTML在到达客户端之前在服务器上渲染,这是必要的但不充分的。你仍然需要正确的canonical标签、合理的sitemap、正确的元数据、结构化数据和快速的服务器响应时间。SSR解决了JavaScript渲染问题。它不能解决架构问题。

Contentful 在 SEO 方面比 Sanity 更好吗?

两个CMS都不直接影响你的SEO,它们都是无头的,所以对你渲染的HTML没有意见。问题是哪一个更容易对SEO相关的内容字段进行建模。两者都有SEO字段插件。Sanity的GROQ查询语言在塑造前端所需的确切数据方面给你更多灵活性,这可以更容易地构建清晰的元数据管道。但这是开发者体验论证,不是SEO论证。

我如何在无头设置中处理 hreflang?

与处理任何元数据相同,从你的CMS数据生成服务器端数据并将其注入每个页面的<head>中。复杂性在于维护CMS中的locale-to-URL映射,并确保前端正确使用它。如果你在Next.js上,i18n配置会处理大部分路由端的工作;你仍然需要从内容数据中明确渲染<link rel="alternate" hreflang="...">标签。

我应该使用 SSG 而不是 SSR 来获得更好的 SEO 吗?

取决于你的内容更新频率。完全静态生成(SSG)给你最快的TTFB,一切在部署时预构建,但这意味着内容更新只有在重新部署时才上线,除非你使用ISR。对于大多数静态营销网站,SSG配合按需ISR可能是正确的选择。对于内容频繁变化的大型目录,SSR配合积极的CDN缓存和短生命周期的缓存头部更合适。

---

令人不安的真相是,无头堆栈将比以往任何CMS架构都更多的SEO责任放在开发者手中。没有插件可以安装并处理它。从规范化逻辑到网站地图生成再到结构化数据,每个决策都是代码决策。这意味着这些决策中的每一个都可能出错,而大多数团队直到排名已经朝错误方向发展时才会审计它们。

提前行动。像 Googlebot 一样爬取你自己的网站。问题几乎总是在 Google 发现之前可以找到的。

< BACK