从 Google 降权到 Lighthouse 满分:一次博客 SEO 排查实录
起因
博客上线快二十天了,Google Search Console 一直显示收录正常,但搜站名死活翻不到——前五页连影子都没有。更诡异的是,site:jay.pub 能搜到所有页面,说明索引在,但排名像是被冻住了。
直到今晚凌晨三点,我开始排查,发现这是一连串 SEO 基础问题的连锁反应。
排查过程
第一个线索:robots.txt 404
curl -I https://jay.pub/robots.txt 直接返回 404。
后端根本没注册这个路由,nginx 又把所有非静态路径 proxy 到 Go 服务,请求落到 Gin 的 NoRoute,返回 404。
更糟的是,翻 nginx 日志发现 Googlebot 在 7 月 18 日那天反复探测 /robots.txt,每隔 1-3 分钟一次,每次都拿到 404。一个连 robots.txt 都没有的站点,爬虫凭什么信任你?
第二个线索:文章页 meta description 全站雷同
随便打开一篇文章,看 HTML 源码:
<meta name="description" content="收集世界的温柔,亦容世间万般不完美。">
所有文章页的 meta description 都是同一个站点级描述。原因在 render() 函数:
func (h *Handler) render(c *gin.Context, name string, data gin.H) {
ss := h.Settings()
data["Description"] = ss.Description // 无条件覆盖
// ...
}
handler 传入的文章摘要被这行直接覆盖了。Google 看到所有文章描述重复,自然降权处理。
第三个线索:没有 canonical、og:type 错误
- 没有
<link rel="canonical">,带 UTM 参数的 URL 会被当成不同页面 - 文章页
og:type是website,应该是article - 管理后台和登录页没有
noindex,虽然 robots.txt 屏蔽了,但那是建议不是强制
修复清单
一次性全修了,按影响排序:
1. 新增 robots.txt 和 sitemap.xml
// /robots.txt
User-agent: *
Disallow: /admin
Disallow: /login
Allow: /
Sitemap: https://jay.pub/sitemap.xml
这里有个细节:Allow: / 放在 Disallow 后面。有些非标准爬虫按顺序匹配,先 Disallow 命中屏蔽规则,再 Allow 兜底,这样才不会因为先命中 Allow 而无视后面的屏蔽。
sitemap 用事件驱动缓存——文章增删改/发布状态切换时主动重建,爬虫请求直接读内存,零 DB 查询。
2. 修复 meta description 覆盖 bug
if _, ok := data["Description"]; !ok {
data["Description"] = ss.Description
}
handler 传了 Description(文章摘要)就用文章摘要,没传才回退到站点描述。
3. 补全 canonical 和 og 标签
<link rel="canonical" href="{{.CanonicalURL}}">
<meta property="og:type" content="{{.OGType}}">
<meta property="og:locale" content="zh_CN">
文章页的 OGType 传 article,其他页默认 website。
4. 管理页加 noindex
admin、login、admin_write 三个模板的 <head> 加:
<meta name="robots" content="noindex,nofollow">
双保险——robots.txt 是建议,meta 标签是强制。
顺手的性能和无障碍优化
SEO 修完后跑了一次 Lighthouse,发现还有提升空间,一并修了:
性能
- 所有非关键 JS 加
defer属性,消除渲染阻塞 - 修复 og-image.png 等 3 张图片因文件权限(600)导致的 403
无障碍
- footer 链接颜色
blue-500→blue-700,对比度从 3.2:1 提到 6.3:1 --text-light变量加深到#546e7a,确保 WCAG AA 通过- 首页和文章页加
<main>语义标签 - 代码高亮的注释色和字符串色加深,通过对比度标准
结果
Lighthouse 双端评分
| 维度 | 分数 |
|---|---|
| 性能 | 100 |
| 无障碍 | 100 |
| 最佳做法 | 100 |
| SEO | 100 |
Core Web Vitals 实测
| 指标 | 值 |
|---|---|
| LCP | 0.45s |
| CLS | 0 |
| INP | 32ms |
Google 收录
修复后第二天晚上,无痕搜索域名,5 个核心页面全部出现:
- 首页
/ - 关于
/about - 更新日志
/changelog - 两篇文章页
文章页的搜索结果描述已经是文章摘要,不再是站点级描述——说明 Googlebot 已重新抓取并采纳了新的 meta description。
几个踩坑点
1. 部署时漏同步模板
改了 base.html 但只 scp 了二进制和 version.json,没同步 templates 目录。模板是运行时从文件系统读的,远程一直是旧模板,导致改了半天的 footer 版本号动态化死活不生效。
教训:部署清单要固化——二进制 + 模板 + 静态资源 + version.json,缺一不可。
2. Lighthouse 对比度检测的局限
代码高亮颜色用 CSS !important 覆盖了内联 style,实际渲染颜色已经改了,但 Lighthouse 读的是原始 DOM 属性,仍然报对比度不足。
结论:Lighthouse 分数是参考不是目的,真实用户看到的是改后的颜色,感官更好才是关键。
3. PageSpeed Insights 的网络延迟假象
报告显示首屏加载 804ms,看着吓人。实际上 697ms 是从 PageSpeed 美国机房到香港服务器的网络延迟,主线程任务只有 107ms。真实用户(国内/香港)的 LCP 是 0.45s。
结论:实验室数据受地理位置影响,真实用户数据(CrUX)才是排名依据。
反思
这次排查最大的教训是:SEO 基础问题会叠加放大。
单独看每个问题都不致命——robots.txt 404、meta description 重复、缺 canonical——但叠加在一起,Google 对站点的信任度就崩了。修复时也不能只修一个,得整体排查、一次性修完。
另一个感悟是:技术优化的终点是内容。性能 100 分、SEO 100 分只是入场券,真正决定排名的还是内容质量和外链。技术层面做到极致后,就该把精力放回写作了。
最后,本次改动全部记录在 changelog 里,版本号从 1.1.2 升到 backend 1.2.1 / frontend 1.1.6。对了——
移除了 Herobrine。