外贸站收录延迟排查记:客户端渲染让 Google 等了三周,三种渲染方案的对照结论
适用读者:负责外贸独立站的前端工程师、管自然流量的独立站运营、正在选型渲染架构的技术负责人。你需要对 React 或 Vue 的工程化有基本概念,不需要深入搜索引擎 internals。
改版上线整整三周,运营拿着新品页链接来问:为什么在 Google 里搜型号加品牌词,翻到第五页都没有我们的页面?后台明明显示 Googlebot 天天来抓。我打开 view-source 看了一眼,心里就凉了半截——返回给 Googlebot 的原始 HTML 里,body 只有一行 <div id="root"></div>。这篇就把这次做搜索引擎优化(Search Engine Optimization, SEO)排查的全过程、数据对照和三种渲染方案的取舍写清楚,给同样在做网站优化的人一个可以直接抄的复盘。
改版留下的债:一个纯前端渲染的 SPA
先交代背景。这个外贸独立站原来是一套 PHP 模板站,速度慢但收录一直稳定。去年 Q4 改版,选了 React 单页应用(Single Page Application, SPA)加后端 API 的架构:前端全部客户端渲染(Client-Side Rendering, CSR),页面内容由浏览器拉 JS、再请求接口拼出来。开发体验确实好,上线两个月内迭代了三十多个需求,没人觉得有什么问题。

问题出在收录上。改版前 Google 大约 48 小时内就能收录新上的产品页;改版后,9 月 2 日上线的一批 40 个新品页,到 9 月 23 日还有 27 个没进索引。中间我们试过在 Search Console 里手动「请求编入索引」,队列排了四天才有响应,响应结果还是「已抓取 - 尚未编入索引」。
关键结论先放这里:CSR 不是不能被收录,而是把收录从一个「抓取即完成」的动作,变成了一个依赖二次渲染队列的异步动作。队列有多长,你的收录时延就有多长。
排查第一步:view-source 和检查元素是两份 HTML
这次排查里最直观的一步,也是后来我跟团队反复讲的一课:view-source: 看到的和「检查元素」看到的,可能完全是两个页面。
view-source: 拉到的是服务器原始响应,等价于 Googlebot 第一阶段拿到的东西;「检查元素」看到的是浏览器执行完 JS 之后的 DOM,等价于 Googlebot 第二阶段渲染后的结果。我们两个一对比,差异大到离谱:
- view-source 里的 body:一个空的挂载点,加 6 个
<script>标签,正文文本约 0 字; - 检查元素里的 body:完整产品描述、规格参数表、FAQ,正文文本约 4200 字。
也就是说,Googlebot 第一眼看到的是一个没有任何内容的空壳。用 Node 写个小脚本把这件事量化,方便每次发版后跑一遍回归:
// fetch-raw.mjs —— 拉取服务器原始 HTML,量化空壳程度
// 运行方式:node fetch-raw.mjs <目标URL>,Node 18+ 自带 fetch,无需装依赖
const url = process.argv[2];
const res = await fetch(url, {
// 关键:不要跟随后端给爬虫的特殊跳转,只看普通用户拿到的响应
redirect: "follow",
headers: { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)" },
});
const html = await res.text();
// 提取 body 内部内容,统计纯文本长度(去掉标签后的字符数)
const body = html.match(/<body[^>]*>([\s\S]*?)<\/body>/i)?.[1] ?? "";
const textLen = body.replace(/<[^>]+>/g, "").trim().length;
const scripts = (html.match(/<script/g) ?? []).length;
// 判定标准:原始正文 < 200 字且 script 占比高,基本可判为 CSR 空壳
console.log(`原始正文文本长度: ${textLen}`);
console.log(`script 标签数量: ${scripts}`);
// 期望值参考:我们站改造前这个数字是 12,改造后(SSG)是 3800+
这个脚本现在是我们 CI 里的固定检查项,正文文本长度低于阈值就直接报警。当时第一次跑出来的数字是 8——8 个字符,基本就是转义后的换行和空格。
原理与机制:Googlebot 的两阶段抓取和渲染队列
要理解为什么「三周才进索引」,得把 Googlebot 的工作机制拆开看。它对 JS 页面的处理是两个阶段:
第一阶段是抓取(Crawl),只拿原始 HTML、解析链接、入队。第二阶段是渲染(Rendering),把页面丢进一个基于 Chromium 的无头浏览器里跑完 JS,再从渲染后的 DOM 里提取内容和链接。这两阶段之间隔着一个全局共享的渲染队列。
flowchart LR
A[调度器从待抓取队列取 URL] --> B[第一阶段: 抓取原始 HTML]
B --> C{HTML 里是否有实质内容?}
C -- 有 --> D[直接解析提取, 进入索引流程]
C -- 没有/极少 --> E[页面进入渲染队列等待]
E --> F[第二阶段: 无头 Chromium 执行 JS]
F --> G[提取渲染后 DOM 与新发现的链接]
G --> H[进入索引评估流程]
这个渲染队列的优先级逻辑没有官方文档明说,但官方在 JavaScript SEO 的帮助文档里确认了渲染是「延后且按需」的,队列资源有限。站点权重越高、被抓取频率越高,排得越靠前;反过来,一个收录历史浅的新站,排几个星期不算稀奇。我们的 40 个新品页就是这么在队列里排队等了三周。
更麻烦的是抓取预算(Crawl Budget)被 JS 拖耗的问题。我们站每个页面平均带 14 个 JS 资源请求,Googlebot 渲染时要挨个下载执行。9 月中旬日志里能看到,Googlebot 每天固定消耗大约 6000 次请求,其中大量是静态资源,真正的新产品页抓取量反而被挤占。对中小站点来说,这是 CSR 在网站优化里最隐蔽的代价:你交的抓取预算,一大半花在了「让 Googlebot 看懂页面」这个本可以省掉的环节上。
用 URL Inspection 做渲染后 HTML 对照
Search Console 的网址检查(URL Inspection)工具提供了「查看已抓取的网页」和「测试实际网址」两个入口,后者会现场跑一遍渲染,把渲染后的 HTML 给你看。这是排查 CSR 问题时最有用的官方工具。
我们当时对照了三个页面,发现的典型问题记录如下:
- 渲染后 HTML 里产品标题正常,但结构化数据没有——因为结构化数据是我们用 JS 注入的,渲染阶段有时超时没跑完;
- 「测试实际网址」的加载状态里出现过
Failed to load resource两次,对应一个挂在内网 CDN 预热前地址的图片; - 页面可交互时间(Time To Interactive)在模拟环境里超过 9 秒,渲染队列里排队时更久。
把渲染前的原始 HTML 和渲染后的 HTML 各存一份 diff,是后面做方案对照的基线。没有这个基线,改造完你说不清到底改善了什么。
三种方案对照:SSR / SSG 预渲染 / 动态渲染
确认问题后我们拉了三个候选方案,逐个评估。先给结论表,再讲取舍过程。
| 维度 | 服务端渲染(SSR) | 静态站点生成(SSG)预渲染 | 动态渲染(Dynamic Rendering)过渡 |
|---|---|---|---|
| 首屏给爬虫的内容 | 每次请求实时生成 | 构建时预先生成 | 爬虫命中预渲染快照 |
| 改造工作量 | 大,组件需兼容服务端执行 | 中,加构建期抓取与写盘 | 小,加一层代理分流 |
| 新品页收录时延 | 分钟级 | 分钟级(重构建后) | 短期无效,依赖快照更新 |
| 长期维护成本 | 高(服务器、缓存、水位) | 中(构建时长随页面数增长) | 高(两套渲染要长期同步) |
| 对 SEO 的意义 | 彻底解决 | 彻底解决 | 止血方案,非终态 |
几个关键取舍点:
SSR 一步到位但门槛最高。我们的产品页里有一半内容依赖登录态和地区定价,SSR 意味着这些逻辑全部要理出服务端安全的版本,团队只有两个前端,预估六周起步,还可能埋一堆水合(Hydration)不一致的坑。
SSG 预渲染最后胜出的原因:产品页本质是「读多写少」,一天上新二三十个 SKU,完全可以在新品上架的发布流程里触发一次增量预渲染,把页面变成纯静态 HTML 直接吃 CDN。这样 Googlebot 第一阶段抓到的就是全量内容,两阶段合并成一个阶段,收录时延直接砍掉渲染排队的时间。
动态渲染我们只当止血带。它的思路是按 User-Agent 识别 Googlebot、Bingbot 这类爬虫,把请求转发给一个预渲染服务,返回已经执行完 JS 的 HTML 快照。改造量最小,理论上两天能上,但它有三个硬伤:UA 判断要长期维护、快照服务本身要保可用性、快照内容和真实页面永远有时间差。官方文档也明确说了这是过渡方案,不推荐长期使用。
给爬虫分流的核心逻辑不复杂,当时止血版本的代码骨架长这样:
// server.js —— 动态渲染止血版:给爬虫吐预渲染快照
// 依赖:express、prerender-node,Node 16+,PRERENDER_TOKEN 配在环境变量里
const express = require("express");
const prerender = require("prerender-node");
const app = express();
// 只对声明过自己是爬虫的 UA 生效,正常用户照旧走 SPA,不影响体验
app.use(
prerender.set("prerenderToken", process.env.PRERENDER_TOKEN)
.set("protocol", "https")
);
// 静态资源与 SPA 入口
app.use(express.static("dist"));
// 兜底:非爬虫请求统一回落到 index.html,交给前端路由
app.get("*", (req, res) => {
res.sendFile(require("path").join(__dirname, "dist", "index.html"));
});
// 健康检查给监控用,快照服务挂了要能第一时间知道
app.get("/healthz", (req, res) => res.send("ok"));
app.listen(3000, () => console.log("render proxy on :3000"));
上线前在预发环境用 curl -A "Googlebot" 验证分流是否命中,再用「测试实际网址」确认渲染结果,这一步不能省——我们第一次配的时候把 UA 白名单写反了,差点把正常用户也导去快照服务。
改造落地:发布流程挂上增量预渲染
最终落地的是 SSG 预渲染为主、动态渲染为辅的过渡架构。方案分铺开的时序大概是这样:
flowchart TD
A[确认 CSR 空壳问题] --> B[止血: 动态渲染代理上线]
B --> C[第 2-4 周: 预渲染管线开发]
C --> D[新品发布流程接入增量预渲染]
D --> E[存量 800 页全量预渲染一次]
E --> F[下线动态渲染, 纯静态 + CDN]
F --> G[SSR 评估推迟到多语言站点重构时再做]
发布流程的接入比想象中顺:运营上架新品后,发布系统调一个内部接口,预渲染 worker 抓取该页渲染结果写进静态目录,CDN 缓存刷新,前后大概 40 秒。真正费劲的是存量 800 个产品页的历史数据清洗——不少老页面的规格表是图片,预渲染出来内容还是薄,这些页面单独排了优先级重做。
改造前后的数据对照是我们跟管理层汇报的核心,也是这篇里最值得留给后来人的一张表:
| 指标 | 改造前(CSR 空壳) | 止血期(动态渲染) | 改造后(SSG 预渲染) |
|---|---|---|---|
| 新品页进索引时延(中位数) | 19 天 | 6 天 | 26 小时 |
| 原始 HTML 正文文本长度 | 8 字符 | 约 3900 字符 | 约 4100 字符 |
| Googlebot 日均请求中浪费在 JS 上的占比 | 约 62% | 约 41% | 约 9% |
| 收录产品页数(30 天窗口) | 143 / 240 | 189 / 240 | 226 / 240 |
| 渲染队列相关「已抓取未编入索引」堆积 | 27 个 | 9 个 | 2 个 |
数据来源是我们自己的 Search Console 和 Nginx 访问日志统计,时间窗是 2026 年 7 月到 9 月,别拿去和别的行业横比,但趋势是可信的:收录时延从 19 天压到 26 小时,靠的不是什么高级技巧,就是让 Googlebot 第一阶段就能拿到全部内容。
Bing 和百度:别把 Google 的经验直接照搬
排查期间顺手看了另外两家,差异值得单独记一笔。
Bing 的爬虫对 CSR 有一定执行能力,但实测渲染触发比 Google 更保守,我们的新品页在 Bing 上同样延迟,只是程度轻一些。百度的情况更严格:它的抓取体系对 JavaScript 渲染的支持长期有限,纯 CSR 站点在百度侧的收录问题比 Google 严重得多,很多外贸站团队只盯 Google,等哪天想接百度流量才发现坑更深。所以如果你的网站优化目标包含多引擎,CSR 的债务是按引擎数翻倍计算的。这条经验后来被我们写进了前端选型 checklist。
误区澄清
最后澄清两个这次复盘里反复被问到的误区。
一个误区是「Google 不是能渲染 JS 吗,等就行」。能渲染,但渲染是延迟的、排队的、消耗抓取预算的。对收录时延敏感的电商新品、活动页,等的成本就是实打实的流量损失,这个等不起。
另一个误区是「上了 SSR/SSG 就等于做了网站优化」。渲染只是技术 SEO 的地基,地基之外还有结构化数据、内链、页面速度这些活,地基不打后面全是空中楼阁。生成式搜索(GEO)兴起之后,爬虫对「拿得到完整 HTML」的要求只会更高,这次改造打底的架构,也算提前给下一步铺了路。
渲染方案没有标准答案,只有和团队规模、业务节奏匹配的选择。你在外贸站收录上踩过什么坑,欢迎评论区交流。
参考与延伸
- Google 搜索中心:了解 JavaScript SEO 基础知识 — https://developers.google.com/search/docs/crawling-indexing/javascript/javascript-seo-basics
- Google 搜索中心:Google 抓取工具概览 — https://developers.google.com/search/docs/crawling-indexing/overview-google-crawlers
- Google 搜索中心:网址检查工具使用说明 — https://developers.google.com/search/docs/monitoring-debugging/inspect-urls
- Bing Webmaster Tools 帮助文档 — https://www.bing.com/webmasters/help/help-center-661155ed
收录延迟 · 客户端渲染 · SSR · SSG 预渲染 · 动态渲染 · Google Search Console · 外贸独立站 · 抓取预算