双语网站 SEO 迁移:301、canonical 与 hreflang 的验收方法
开发实践
把 guides 文件夹改成 articles,页面能打开,只完成了迁移的一部分。旧地址能否到达同一篇文章,搜索引擎是否收到一致的新地址,分享图片有没有失效,才决定这次改名是否完整。这里记录本站的实现与可复用的验收方法;本地检查能验证输出,不能替代上线后的抓取与收录观察。
把改名写成地址映射,而不是全局字符串替换
本站保留文章 slug,中文与英文分别从 /zh/guides、/en/guides 迁往 /zh/articles、/en/articles。旧链接应指向对应文章,不能一律丢到文章首页。查询参数也要保留,避免已有分享链接的来源信息消失。
重定向规则需要区分页面与静态文件。/articles/codex-subscription 是无语言入口,应落到默认英文;/articles/某张图片.jpg 则是公开资源,不能加上 /en 变成一个不存在的页面。迁移时把图片目录和 OG 图片目录也一起改了,旧资源入口保留永久跳转。
www 的旧地址需要同时改域名和目录,本站在同一次跳转里完成,减少先改域名再改目录的链。规则只匹配真正的 guides 路径:/guides-old 不应误命中。下表是验收样例,不是新的导航链接。
| 请求样例 | 目标 / 结果 | 检查点 |
|---|---|---|
| /zh/guides/codex-subscription | 301 → /zh/articles/codex-subscription | 同语言、同文章,目标 200 |
| /zh/guides?page=2 | 301 → /zh/articles?page=2 | 保留参数;第 2 页存在时为 200 |
| /articles/codex-subscription | 301 → /en/articles/codex-subscription | 默认语言入口 |
| /og/guides/旧图片.jpg | 301 → /og/articles/旧图片.jpg | 仅对确有文件的旧资源验收 |
| /guides-old | 404 | 不误匹配前缀 |
中文页 canonical 指向自己,语言关系另行声明
完整的中英文文章是两份有独立价值的内容。中文页 canonical 指向中文新地址,英文页指向英文新地址;hreflang 负责说明它们是语言对应版本。把中文 canonical 全指向英文,相当于给出了不同的规范化信号,不能用来代替语言关系。
下面是中文文章的目标标记。英文页面也需要包含这组相互对应的 alternate,并把自己的 canonical 改成英文 URL。x-default 在本站选择英文版本,符合默认入口;它并不是第三篇翻译,也不是所有双语网站都必须照搬的选择。
绝对地址统一使用生产域名,不能混入 localhost、www、旧目录或语言错误的路径。审核时按一篇文章的一对页面检查,而不是只看中文页上出现过 hreflang 这个词。
<link rel="canonical"
href="https://evanlong.me/zh/articles/codex-subscription">
<link rel="alternate" hreflang="zh-CN"
href="https://evanlong.me/zh/articles/codex-subscription">
<link rel="alternate" hreflang="en"
href="https://evanlong.me/en/articles/codex-subscription">
<link rel="alternate" hreflang="x-default"
href="https://evanlong.me/en/articles/codex-subscription">正文、搜索摘要与分享信息,要从同一份数据产生
本站的文章记录保存双语标题、描述、日期、主题和图片,列表、详情页、generateMetadata 与 sitemap 从同一份记录生成。这样改一篇标题后,H1、搜索 title、OG / Twitter 标题与 Article headline 不需要手工分别改。品牌后缀由 metadata 辅助函数统一处理,不混进正文标题。
这是减少不一致的实现策略,不是保证排名的技巧。每次仍要检查服务器返回的 HTML:canonical、og:url、语言链接与 JSON-LD 的 url / mainEntityOfPage 指向同一新页面;Article 的作者、日期与图片符合可见内容。结构化数据不应编造评价、销量或 HowTo 步骤来争取搜索展示。
图片还有两种职责:OG 图片供分享卡片读取,正文图片供阅读。本站 OG 图为 1200×630,正文截图保留实际尺寸,带描述性 alt、图注、来源与日期。价格截图记录的是核对时的状态,正文应说明变化边界;alt 解释画面,不能堆一串购买关键词。
分页不是重复页面,别把每页都 canonical 到首页
本站首页只展示三篇,归档每页十篇,使用正常的上一页 / 下一页链接。第 2 页存在时,用 /articles?page=2 表示,并规范化到自己;?page=1 则跳转到没有参数的第一页。不同页包含不同文章,全部指向第一页会模糊这些内容的区别。
当前只有五篇,所以请求第 2 页应返回 404;“保留参数的迁移”不等于“所有分页永远有效”。新增到十一篇时,再验收第二页、语言切换保留 page=2,以及 sitemap 的分页条目。筛选和排序以后若引入参数,应单独决定收录策略,不能默认沿用分页规则。
测试工具也要区分旧 URL 的展示示例与真正的旧链接。这篇正文会讲 /guides 的迁移;仅因 HTML 文本包含这个字符串就判失败,是在禁止案例解释。真正需要禁止的是仍指向旧目录的 canonical、sitemap、图片 src 和站内导航。
发布前查 HTTP,发布后查抓取,别混成一次验收
本地可以检查响应与生成内容:旧入口的状态码和 Location,新入口是否 200,语言版本是否互相对应,图片能否访问,失效 slug 是否 404。下面这个命令用于部署后检查生产域名;本地调试应把域名改成 localhost:3000。不要因为浏览器自动跟随跳转后显示正常,就忽略途中发生了什么。
上线后还要在 Search Console 检查代表性新 URL 的抓取、选定 canonical 与 sitemap 状态,观察旧目录是否逐步被替换。重定向与 sitemap 是帮助迁移的信号;本地全通过无法证明 Google 已抓取,更无法证明排名提升。不要为了结果暂时没变化,再频繁更换目录。
curl -sS -o /dev/null -D - \
'https://evanlong.me/zh/guides/codex-subscription?utm_source=test'
# Run after this migration is deployed.
# Expected: 301, then a Location ending in
# /zh/articles/codex-subscription?utm_source=test
# Check the destination separately: it should return 200.最后衡量的是读者行为,点击不等于订单
订阅文章可以承接具体搜索问题,但设计与开发文章也需要自身成立。商业入口应接在相关判断之后:例如确认需要会员后看套餐,而不是每一节都插入商店广告。文章首先要完成读者打开它时想解决的事。
本站用 shop_click 记录公开的页面路径、入口位置和商品标识,不发送查询参数或订单材料。它只能说明用户点去了哪里;不能据此宣布多少人付了费。个人站与 shop 子域名也不能仅因为域名相近,就假设分析工具已经打通了完整购买路径。
可以按同一篇落地页、同一时间窗口分开看:搜索曝光与点击、文章访问、商品入口点击、已支付订单。比如假设 100 次文章访问有 8 次商品点击,这只能算 8% 的入口点击率;若没有可归因的订单数据,就不能写成 8% 转化率。样本很小时也不应从一两个点击猜哪种标题必胜。需要优化时,一次改一个明确问题,再观察对应指标。