[{"data":1,"prerenderedAt":296},["ShallowReactive",2],{"blog-hreflang-canonical-conflict":3,"blog-prev-hreflang-canonical-conflict":103,"blog-next-hreflang-canonical-conflict":194},{"id":4,"title":5,"author":6,"body":7,"canonical":87,"category":88,"cover":87,"date":89,"description":90,"draft":91,"extension":92,"keywords":87,"meta":93,"navigation":94,"noindex":91,"ogImage":87,"path":95,"seo":96,"seoDescription":87,"seoTitle":87,"stem":97,"tags":98,"updated":87,"__hash__":102},"blog\u002Fblog\u002Fhreflang-canonical-conflict.md","hreflang 和 canonical 打架，多语言站最常见的错","元析智能",{"type":8,"value":9,"toc":77},"minimark",[10,14,18,25,31,37,41,44,47,50,53,56,59,62,65,68,71,74],[11,12,13],"p",{},"canonical 管的是\"哪个地址是主版本\"，hreflang 管的是\"这组页面是同一内容的不同语言版本\"。两件事分工明确，但配在一起时特别容易互相拆台。最常见的错是跨语言 canonical：中文页指向英文页，理由是\"英文站是主站\"。这一指，中文页就永远不单独排名了。",[15,16,17],"h2",{"id":17},"三种冲突形态",[11,19,20,24],{},[21,22,23],"strong",{},"跨语言 canonical","：中文页 canonical 到英文对应页。看起来是\"集中权重\"，实际是告诉搜索引擎\"中文页不用单独存在\"。",[11,26,27,30],{},[21,28,29],{},"语言组里的地址不是主版本","：hreflang 指向的 URL 自己又被 canonical 到别处，整组关系混乱。",[11,32,33,36],{},[21,34,35],{},"x-default 指向一个被 canonical 掉的页面","：兜底版本不存在，等于没兜底。",[15,38,40],{"id":39},"_2026-年-1-月那个出海-saas","2026 年 1 月那个出海 SaaS",[11,42,43],{},"英文站是主域，中文站是子域。技术团队按\"主站优先\"的思路，把中文页 canonical 到英文对应页，同时两边又互相写了 hreflang。结果中文关键词的搜索结果全部展示英文页，中文站的自然点击只有英文站的 4%，客服天天收到\"你们官网为什么是英文\"的反馈。",[11,45,46],{},"改成同语言自指 canonical、完整 hreflang 组（含自引用和 x-default）之后，第 7 周中文站的自然点击涨了 5.6 倍。改动本身只有一行模板，前后差了一个季度。",[15,48,49],{"id":49},"验证方法",[11,51,52],{},"Screaming Frog 跑全站，导出 canonical 和 hreflang 两列交叉比对：canonical 指向的域名是否和本页语言一致、hreflang 组里的每个地址是否都 200 且 canonical 自指。抽 10 个页面手工看源码确认，工具报告偶尔会因为 JS 渲染漏读。",[11,54,55],{},"GSC 的\"网页\"报告可以按目录看展示份额，哪个语言版本的展示量明显低于它的页面占比，就去查那一组的配置。",[15,57,58],{"id":58},"我们的检查清单",[11,60,61],{},"每次接多语言站，我们照这四条过一遍：每个页面的 canonical 是否指向同语言自己；hreflang 组是否包含自引用；x-default 是否指向一个可访问的主版本；组里每个 URL 是否都返回 200 且没被 robots 屏蔽。四条全过，配置层面就算干净了。",[11,63,64],{},"再用 GSC 的展示数据交叉验证：中文目录的页面数占全站 40%，展示量却只有 5%，那这个语言版本的配置大概率有问题。数据永远比源码先说话。",[15,66,67],{"id":67},"正确的配置长什么样",[11,69,70],{},"中文页：canonical 指向自己，hreflang 列出自己、英文页、其他语言页，x-default 指向英文版。英文页同理。没有哪个语言版本\"更主\"。",[15,72,73],{"id":73},"立场",[11,75,76],{},"多语言站先立一个前提：每个语言版本都是独立站点，服务不同的用户群。语言之间不是主从关系。想清楚这一点，canonical 就不会乱指了。",{"title":78,"searchDepth":79,"depth":79,"links":80},"",2,[81,82,83,84,85,86],{"id":17,"depth":79,"text":17},{"id":39,"depth":79,"text":40},{"id":49,"depth":79,"text":49},{"id":58,"depth":79,"text":58},{"id":67,"depth":79,"text":67},{"id":73,"depth":79,"text":73},null,"技术SEO","2026-03-12","英文页 canonical 指向中文页、中文页 hreflang 指向英文页，这种配置会让两个版本互相抵消。我们用一个 2026 年 1 月的客户站讲清正确关系、三种冲突形态和验证方法。",false,"md",{},true,"\u002Fblog\u002Fhreflang-canonical-conflict",{"title":5,"description":90},"blog\u002Fhreflang-canonical-conflict",[99,100,101],"hreflang","canonical","多语言","DZzGyUZlJ7S65t1gwaJvbdythbuAcUY6tKBGfOpnPQo",{"id":104,"title":105,"author":6,"body":106,"canonical":87,"category":182,"cover":87,"date":183,"description":184,"draft":91,"extension":92,"keywords":87,"meta":185,"navigation":94,"noindex":91,"ogImage":87,"path":186,"seo":187,"seoDescription":87,"seoTitle":87,"stem":188,"tags":189,"updated":87,"__hash__":193},"blog\u002Fblog\u002Fseo-cron-jobs.md","跑 SEO 杂活的六个定时任务，怎么排才不出错",{"type":8,"value":107,"toc":174},[108,111,114,117,120,123,126,129,132,135,138,141,144,147,150,153,156,159,162,165,168,171],[11,109,110],{},"2026 年 3 月盘了一下我们跑的定时任务，六个，每周大概省下六小时机械劳动。定时任务的风险不在写，在没人管。一个静默失败的任务，比没有这个任务更危险，因为你会以为数据是对的。",[15,112,113],{"id":113},"六个任务",[11,115,116],{},"GSC 数据拉取，每周一凌晨；站点地图提交检查，每周一上午；死链扫描，每周二；排名快照，每周三；日志简报，每天 9 点；收录抽查，每周五。",[11,118,119],{},"这六个覆盖了我们日常要看的全部数据。再往上加就是过度自动化，比如自动改 titles、自动发文章，这类我们不做，改错了没人拦。",[15,121,122],{"id":122},"排期原则",[11,124,125],{},"别都放周一。周一凌晨是好时间，但六个任务一起跑，一个失败会影响后面的。我们按数据依赖排：先拉 GSC 数据，再跑排名快照，最后生成报告。",[11,127,128],{},"每个任务要能单独重跑，不依赖前面的中间文件。这条听着简单，实际写的时候很容易把状态存在临时文件里，一失败就得从头来。",[15,130,131],{"id":131},"失败处理",[11,133,134],{},"最危险的是静默失败。脚本报错退出，但没人看到，第二天报表是空的，大家以为这个站没数据。",[11,136,137],{},"我们的做法是心跳：每个任务跑完写一行记录到表里，包括时间和状态。另有一个检查任务，早上 8 点看所有任务最近一次成功时间，超过 26 小时没成功就在群里 @ 人。",[11,139,140],{},"26 小时这个阈值是因为日任务和月任务混在一起。日任务超过 26 小时没跑肯定有问题，周任务则由它自己的下一次运行覆盖。",[15,142,143],{"id":143},"谁维护",[11,145,146],{},"指定一个人负责，不是“大家一起看”。没有明确负责人，出问题就是互相等。",[11,148,149],{},"每季度 review 一次，把过去三个月没被任何人看过的任务删掉。我们上个季度删了一个排名监控任务，因为客户根本不看那份数据，白跑半年。",[15,151,152],{"id":152},"上线前先手动跑三次",[11,154,155],{},"定时任务最坑的是“看起来在跑”。第一次跑就写错字段的情况太常见，凌晨出错，三天后才被发现。",[11,157,158],{},"我们现在的规矩是手动跑三次，三次输出一致再挂 crontab。多花十分钟，省掉一次事故。",[15,160,161],{"id":161},"我们的排期表长什么样",[11,163,164],{},"任务用 crontab 跑，配置文件进 git，改动要提交合并请求。听着像小题大做，但你不会想体验“谁上周改了这个脚本”这种排查。",[11,166,167],{},"每个任务旁边写一行注释：它解决什么问题、失败会怎样、谁负责。三个月后自己都忘了当初为什么加。",[11,169,170],{},"日志统一写到固定目录，按任务名命名，保留 30 天。出问题先看最后 50 行，八成错误都在那里。",[11,172,173],{},"自动化不是越多越好。六个够用，第七个开始就是给自己找活干。",{"title":78,"searchDepth":79,"depth":79,"links":175},[176,177,178,179,180,181],{"id":113,"depth":79,"text":113},{"id":122,"depth":79,"text":122},{"id":131,"depth":79,"text":131},{"id":143,"depth":79,"text":143},{"id":152,"depth":79,"text":152},{"id":161,"depth":79,"text":161},"SEO","2026-03-11","六个定时任务每周省下六小时，但静默失败比不做更危险。这篇写任务清单、排期原则、心跳告警，以及我们每季度砍任务的规矩，看完能照着搭。",{},"\u002Fblog\u002Fseo-cron-jobs",{"title":105,"description":184},"blog\u002Fseo-cron-jobs",[190,191,192],"自动化","定时任务","工作流","ut1Rob-FJ1zVcaOU9G0N9yxELWMCWWLwj02kRpti8Qo",{"id":195,"title":196,"author":6,"body":197,"canonical":87,"category":88,"cover":87,"date":285,"description":286,"draft":91,"extension":92,"keywords":87,"meta":287,"navigation":94,"noindex":91,"ogImage":87,"path":288,"seo":289,"seoDescription":87,"seoTitle":87,"stem":290,"tags":291,"updated":87,"__hash__":295},"blog\u002Fblog\u002Fself-host-fonts-china.md","字体放 Google Fonts 还是自托管，国内首屏差了一秒多",{"type":8,"value":198,"toc":277},[199,202,205,208,211,214,217,220,232,235,238,249,252,255,258,261,264,267,270],[11,200,201],{},"去年 11 月我们做过一次对比：同一个页面，字体分别放 Google Fonts 和放国内 CDN 自托管，从北京、上海、广州三地各测 50 次。Google Fonts 的字体请求 P75 是 1.2 秒，有 6 次超时超过 3 秒；自托管的 P75 是 180 毫秒，没有超时。",[11,203,204],{},"这个差距比图片优化大得多。字体是阻塞渲染的资源，它慢一秒，首屏就晚一秒。",[15,206,207],{"id":207},"为什么会差这么多",[11,209,210],{},"两个原因。一是 Google Fonts 的域名和节点在境外，国内访问要过国际出口，高峰期不稳定。二是它的 CSS 和字体文件来自不同域名，多两次 DNS 和 TLS。",[11,212,213],{},"自托管把字体和页面放在同一个域名或者同一个 CDN，省掉域名解析和连接建立，路径短，稳定性也好。",[15,215,216],{"id":216},"我的建议很直接",[11,218,219],{},"面向国内用户的软件站，字体必须自托管，没有例外。做跨境的站，英文站可以用 Google Fonts，但如果国内访问占比超过两成，也建议自托管，用同一份文件走全球 CDN。",[11,221,222,223,227,228,231],{},"自托管要做三件事：字体子集化、",[224,225,226],"code",{},"font-display"," 设置、正确的 CORS 头。第三点常被忽略，字体文件跨域加载需要 ",[224,229,230],{},"Access-Control-Allow-Origin","，配错了浏览器直接拒绝使用，控制台一堆 CORS 报错。",[15,233,234],{"id":234},"一个踩过的坑",[11,236,237],{},"有个客户把字体放在自己的静态资源域名上，那个域名没接 CDN，走的是源站单线机房。字体文件 300KB，南方用户下载要 2 秒。挪到主站 CDN 之后降到 200 毫秒。",[11,239,240,241,244,245,248],{},"这说明自托管不等于快，得确认字体文件走的是 CDN 而不是源站。查法很简单：网络面板里看字体请求的响应头有没有 CDN 标识，或者直接看 ",[224,242,243],{},"age"," 和 ",[224,246,247],{},"server"," 字段。",[15,250,251],{"id":251},"第三方字体服务值不值",[11,253,254],{},"国内有几家做网页字体分片的服务，用它们的 CDN，按流量计费。适合不想自己管子集的团队，代价是每年几千到几万的费用，以及多一个依赖。",[11,256,257],{},"我们的判断：日访问量十万以下，自托管更划算；超过这个量级，第三方服务的分片和缓存策略往往比自建做得好。",[15,259,260],{"id":260},"一条底线",[11,262,263],{},"不管选哪种，字体文件不要超过 300KB，首屏只加载真正用到的那个。这两条做不到，换什么方案都救不了首屏。",[15,265,266],{"id":266},"一个简单的验收方法",[11,268,269],{},"改完之后，让北京、上海、广州各一个真实用户打开页面，看网络面板里字体请求的耗时和状态码。三个地方都稳定在 300 毫秒以内算过关。",[11,271,272,273,276],{},"再检查一遍缓存头：字体文件名带 hash、缓存一年、不要设 ",[224,274,275],{},"Vary: User-Agent","。有些 CDN 默认带这个头，会把缓存命中率打下来，字体每次都回源，等于没自托管。",{"title":78,"searchDepth":79,"depth":79,"links":278},[279,280,281,282,283,284],{"id":207,"depth":79,"text":207},{"id":216,"depth":79,"text":216},{"id":234,"depth":79,"text":234},{"id":251,"depth":79,"text":251},{"id":260,"depth":79,"text":260},{"id":266,"depth":79,"text":266},"2026-03-13","同一页面在北京上海广州各测 50 次：Google Fonts 字体请求 P75 1.2 秒、6 次超时 3 秒，自托管 P75 180 毫秒。自托管要做的三件事，以及一个把字体放在源站的坑。",{},"\u002Fblog\u002Fself-host-fonts-china",{"title":196,"description":286},"blog\u002Fself-host-fonts-china",[292,293,294],"自托管字体","国内访问","字体加载","A_nndNXPfQghyuu2sfhIahevd1Uwq3JxZM1_R0UtuUI",1794088107689]