问题是被一次 SEO 检查发现的:随机抓 10 个页面(首页、产品详情、案例详情、新闻详情),对比 HTML 的 MD5,全部一样。打开源码,只有 <div id="app"></div> 和一堆 script 标签。 这意味着从爬虫视角看,我们建了 780 个页面,实际只有 1 个。 为什么不能直接上 Nuxt 最直接的方案是把 Vue SPA 改成 Nuxt SSR。但评估后放弃了:现有项目有大量依赖 window 和历史路由的代码,改造成本高,而且后台管理和前台在同一个工程里,迁移会牵连一大片。 另一个方案是预渲染成静态文件,但内容来自数据库(产品、案例、新闻每天都在变),每次变更都要重新构建,运维上不现实。 最后选了第三条路: 在 ASP.NET Core 的 SPA fallback 里做轻量 SSR ——不渲染整个 Vue 组件树,而是按路由拼一份"最小可读"的 HTML:正确的 title、description、canonical、OG、JSON-LD,加上一段纯文本正文。 中间件的结构 核心是一个 SpaPrerender 类,按 path 分支: GET / → 首页(静态注入版 index.html) GET /products → 产品列表(遍历 products 表) GET /products/{id} → 产品详情(Product JSON-LD) GET /cases/{id} → 案例详情 GET /news/{id} → 新闻详情(NewsArticle JSON-LD) GET /templates/{id} → 模板详情 GET /about, /contact → 公司信息页 GET /tools → 工具矩阵(独立页,不加载 Vue) 其它 → 返回原始 index.html 每个分支做四件事:查数据、拼 HTML、注入 head、把正文塞进 <div id="sc-ssr"> 。Vue 挂载后会把这个容器清掉,用户看不到重复内容,但爬虫拿到的是完整信息。 坑一:内页继承了首页的 FAQ 首页那份 index.html 里有我们之前注入的 FAQ 静态块和 FAQPage 结构化数据。预渲染时直接用这份 HTML 做模板,结果每个产品详情页都带着首页的 8 条 FAQ 和一份 FAQPage。 后果是:Google 判定 FAQ 内容与页面主题不符,结构化数据被忽略;页面体积也大了 4—7KB。 解法是在内页分支里用正则剥掉带标记的块: 去掉 <!--SC_FAQ_START--> … <!--SC_FAQ_END--> 去掉 <!--SC_FAQ_STATIC_START--> … <!--SC_FAQ_STATIC_END--> 去掉 FAQPage / ProfessionalService 的 ld+json 这里的关键是给每个注入块加 SC_*_START/END 注释标记。没有标记的话,正则匹配很容易误伤正文。 坑二:Vue 把 title 改回去了 预渲染把 title 设成「XX 型号不锈钢法兰 - 越豹科技」,但 Vue 路由守卫里有 document.title = '产品详情 - 实诚科技' ,页面一加载就把正确的标题覆盖了。 浏览器的标签页看着是对的,但爬虫如果执行 JS,读到的就是错的。解法有两个:改路由守卫(要重新打包前端),或者注入一段守护脚本。 我们选了后者:把预渲染的标题存到 window.__SSR_TITLE ,用 MutationObserver 监听 <title> ,被改掉就改回来。 const want = window.__SSR_TITLE; new MutationObserver(() => { if (want && document.title !== want) document.title = want; }).observe(document.querySelector('title'), { childList: true }); 难看,但有效,而且不用动前端构建。 坑三:缓存把新内容挡住了 预渲染结果加了 2 分钟内存缓存,避免每次请求都查库。测试时发现改了产品描述,线上十分钟都没变——不是缓存的问题,是浏览器和 CDN 都在缓存 HTML。 最后按路由区分:列表页 max-age=120 ,详情页 max-age=60, must-revalidate ,tools 页 max-age=120 。调试时统一加 Cache-Control: no-cache 请求头,否则很容易误判「没生效」。 效果 780 多个 URL 的 HTML 各不相同,MD5 唯一率 100%; 每个详情页有独立 title、description、canonical、OG 图和对应类型的 JSON-LD; 页面平均体积增加 3—6KB(纯文本正文),首屏可交互时间无明显变化; 百度收录从 240 条增长到 690 条,产品型号页收录率从 34% 到 92%。 什么情况下值得这么做 如果你的站是 SPA、页面数量在几百到几千、内容来自数据库、又不想推翻重写,这个方案性价比很高。如果页面只有几十个、内容几个月不变,直接预渲染成静态文件更简单。 判断标准就一条:Ctrl+U 能看到正文吗?看不到,就该动手了。
孝感实诚网络科技有限公司(实诚科技)专注网站建设、小程序开发、管理系统定制与软件工具开发,咨询热线 13622369854。
孝感实诚网络科技有限公司(品牌简称「实诚科技」、「实诚网络」,官网 shichenkeji.com)位于湖北省孝感市孝南区,是一家专注企业数字化服务的技术公司。核心团队平均 8 年以上开发经验,10 年技术沉淀,已为 600+ 家企业提供服务,累计交付 1200+ 项目。