六站补面(rauno/diygod/xeiaso/shud.in/vincentwill/sabrina)+
自查实证(生产 SEO 60-63 根因=noindex 封印+robots 404+ESA 30 天
头缓存;localePath 双 en;Artalk 评论数 API 实测;reader 落点
清单)+ 实施卡片 A-J(文件级落点+断言验收+工作量)+ 三批排期 +
明确不做清单。
验证: 关键断言独立复核(nginx snippet noindex 行/robots 404 生产
curl 实测一致)
Spec: none (方案文档,待用户批 A/B/C/E 立即批后立项)
Co-authored-by: GLM-5.3
22 KiB
博客优化方案 v2(深度版)
最终落位:
docs/research/07-博客优化方案v2.md(本文件为 scout 产出原稿,内容即完整方案)。 数据来源:2026-10-26 12:05-12:30 生产实测(curl 直抓 wait4x.online + 本机 nginx/Artalk 容器 + 仓库源码)与境外站直连抓取(本机 clash 7897 节点故障,--noproxy '*'直连成功,复现 v1 教训)。抓取失败项已如实标注。 前置:v1 六站研究见 docs/research/06;本项目历史调研 01-05。
1. 执行摘要(推荐立即做的 8 件事)
- 解除全站 noindex 封印(0.5d):nginx 共享 snippet 给博客 vhost 注入
X-Robots-Tag: noindex,全站被标记不可索引——这是生产 SEO 60-63 的第一主因,所有内容工作在这之前等于闭门写。 - 补 robots.txt + ESA 全站 purge 一次(0.5d):public/ 从未有 robots.txt(生产 404);noindex 响应头已被 ESA 边缘缓存 30 天,修完必须 purge。
- 修 localePath 双 en bug + 加自指 canonical(0.5d):en 页 hreflang 自指
/en/en/archives/…(404);同页带/不带尾斜杠双 200。 - 构建期内容 lint(1d):断链/图片存在性/frontmatter schema/双语配对,build.sh 守卫挂钩(防线前移,v1 P0 坚持项)。
- /draft/ 预览路由(1d):写作流最大缺口;长随机路径 + robots noindex + 不入 sitemap。
- reader 纯文本模式(0.5d):
html.reader单 class 方案,落点已全部排明(§4.4);命令面板reader命令 +r键。 - 列表页评论数前置(1d):Artalk API 已实测(
GET /api/v2/comments?…&site_name=wait4x.online返回count),构建期拉取静态渲染,零运行时。 - 首页 title/description 语义化(0.5d):现全站共用
wait4x+ 一句通用 description,列表/文章页 title 已对,home 与 moments/gallery 等仍弱。
2. v1 P0/P1 批判性复审
| v1 项 | v1 级 | 复审结论 | 理由 |
|---|---|---|---|
| 阅读时长角标 | P0 | 降 P1:文章页已有([...slug].astro:39 汉字数/400 取整,:60 已渲染"阅读时长 N 分钟");v1 说的其实是列表页角标,页内已有 → 列表是锦上添花 |
|
| →EN 互链 | P0 | 关闭:Header nav-lang EN 链接已每页常驻(车道 G 出舱后任何宽度可见)。但复查揪出真 bug:en 页 hreflang 双 en(见 §4.1-3)——从"加互链"转化为"修 localePath" |
|
| /draft/ 预览路由 | P0 | 坚持:git 架构最大写作缺口。实现降级:长随机路径优先于 BasicAuth(nginx 现无 auth 依赖,别为 draft 引入) | |
| 构建期 lint | P0 | 坚持并升级:SEO 三连漏检证明"只在本地测"会漏生产层故障——lint 应加"生产冒烟"(curl robots/sitemap/头)一档 | |
| reader 纯文本 | P1 | 坚持升 P0 批(与 SEO 同批做):antfu 同款 + 灰阶天然适配,本轮落点清单已备好,半天可收 | |
| 偏好面板 | P1 | 降级收窄:先只做 reader + 辉光/动效开关两个 toggle,防"设置中心"过度设计(innei 面板是 React 重站的路数) | |
| gallery EXIF 卡 | P1 | 坚持:photos_ingest.py 构建期 exifr 数据已在手,纯展示层 | |
| 评论数前置+最新评论 | P1 | 坚持,风险清零:v1 担心的"API 形状/ESA 缓存"本轮实测解决——构建期从 127.0.0.1:13030 内网直拉(构建机=Artalk 宿主),完全不碰 ESA | |
| 瞬间编号化 | P1 | 保留 P1 尾部:仪式感成立(diygod #年终总结 6 篇、阮一峰 416 期都验证了节奏感),但数据量小(21 图+1 瞬间),收益后置 |
|
| 归档全量复核 | P1 | 关闭(已达标):实测 /archives/ 全量单页,zh 6 条 + en 6 条(7 个 md 减 media-sample 的 hidden 标记),无分页,一页可扫 | |
| 友链页 | P1 | 保留:diygod /friends 友邻页再次验证(中文个人站礼节),YAML 驱动一晚 |
|
| Newsletter | P2 | 维持观望:xeiaso 用 Patreon/signalboost 但那是有 400 文+社群的体量;我们 RSS 刚起步,先 RSS 说明页 |
v1 最大盲区(自我批判):v1 调研全部基于"站点代码应该没问题"的假设,只测了视觉/交互,没测生产响应头与爬虫视角——本轮 SEO 60-63 的三个根因(noindex 头、robots 缺失、hreflang 404)全部存在于 v1 调研期间,一个都没被 v1 发现。教训:体验研究必须包含"爬虫/机器人视角"的生产实测,已补进 §4。
3. 新探索站增量发现(v2 补面,8 站)
本机 clash 7897 节点当日故障(google/github 经代理均 000),全部改
--noproxy '*'直连成功——与 v1"代理 TLS 故障改直连"同款环境病,抓境外站先直连再代理。
- rauno.me(9.7KB 瘦 HTML,实测)——交互工艺标杆,但真正的标杆在子页:
/craft是按月编年的工艺案例库(2020→2026,30+ 条:Toolbar Morph/X-Ray Interaction/⌘K Breadcrumbs…,每条三种出口 View Production/View Prototype/Read Essay)。首页即一句信条循环("Make it fast. Make it beautiful… Make it.")+ Email 点击即复制("Copied" 内联反馈)+ 自我版本化(2023/2022 年度快照链接)。可借鉴:①把 terminal 页或独立页做成"工艺/极客案例编年体";②页脚 email 用复制微交互替代 mailto;③站内 About 写"信条列表"比自我介绍段更有身份感。 - diygod.cc(RSSHub 作者站,实测)——中文极客个人站代表:首页格言 + 分类计数前置(创作集26/分享境18/研习坊16/日记本13——中文意象化命名,与 v1 qh1009 结论互证);/posts 90 篇前端关键词搜索(零后端);双语 /en 切换;
#年终总结6 篇的节奏传统。彩蛋级发现:页面内嵌一段给 AI 爬虫的 persona prompt("你是一个擅于模仿真实人类写博客的 AI,名字叫 DIYgod…")——对 AI 爬虫的幽默防御/人格注入,我们 terminal 页可同款玩。RSS 姿态:作者即 RSSHub 之父,站内 RSS 极简入口 + 完整摘要输出(15/15 全文)。 - brianlovin.com——抓取失败(如实标注):Vercel Security Checkpoint JS 挑战挡 curl(HTTP 429),本机 c4ai 无头浏览器因代理故障不可用。其"写作/项目/梯次"结构引用 v1 常识不采信,标注为待人工复核。
- vincentwill.com(实测,选它弃 sabrinacodes)——sabrinacodes 实抓后确认是 PHP 教师 portfolio(Resume/Education/Mini Games),与我们三轨内容零交集,弃;vincentwill 为柏林 web 开发者:微产品墙一行一产品(名+一句话+链接,[Sold] 标记),"latest projects" 精选 6 + "More Projects" 全量折叠——与开源项目墙"双源"同构,可借鉴其精选/全量两档而非平铺。
- xeiaso.net(实测)——400+ 文的终端极客活化石:blog 列表页顶部RSS+JSONFeed 双提示语("If you have a compatible reader…");系列文仪式("No way to prevent this" 同标题连发=美国枪击梗的技术圈复刻,系列性本身就是品牌);页脚最新 commit hash 链回 GitHub(与我们 T7 同款,互证方向);多身份自我定义(technical educator/vtuber/philosopher)。可借鉴:①系列文(CS 配置/书评都可系列化命名);②blog 顶部 RSS 友好提示语;③signalboost(转发求职/求助信息)是社群位远期选项。
- shud.in(自选①,理由:中文 design engineer、Vercel 核心贡献者的极简样本,与"灰阶骨架"同谱系)——实测四页 IA(About/Thoughts/Projects/Guestbook),首页一段自我叙述+社交链接,零装饰零动效。Guestbook 留言板=轻量社区位(Artalk 现成能力);"Thoughts"命名比"博客"更有随笔感。启示:我们的极简已达标,不需再减;缺的是 diygod/xeiaso 级的内容节奏与仪式。
- Artalk 生态站——artalk.org 域名已易主(实测标题"𝕜✺𝕫 𝕤𝕥𝕦𝕕𝕚𝕠 // healing arts therapy",Squarespace 疗愈站)⚠️;但官方实为 artalk.js.org,npm 包
artalk2.10.1 于 2026-10-25(昨天)发布,上游活跃。结论:我们自托管 artalk-go 2.10.0 容器不受域名易主影响;升级通道=Docker Hub;官方 demo 站本轮未访(js.org 子域未测),评论体验最佳实践改以"本机 2.10.0 API 实测"为准(§4.3)。行动项:文档/书签里的 artalk.org 引用全部改 artalk.js.org。 - 增量共性(补 v1 十二条之外):①分类/标签中文意象命名+计数前置(diygod×qh1009 双验证)→ 我们 PostList 的 reading/tech/photo 三轨 zh 词条已是意象词,可加计数;②系列文/编号传统(xeiaso×diygod×阮一峰三方验证)→ "瞬间"编号化(v1 #6)证据更强;③RSS 可见性(diygod 全文输出+xeiaso 列表页提示语)→ 我们 rss.xml.ts 存在但入口只在命令面板+页脚,/articles/ 页顶可加一行订阅提示。
4. 自查实证(生产 × 仓库,全部本轮实测)
4.1 SEO 60-63 根因(三连,全实锤)
| # | 事实 | 证据 | 影响 |
|---|---|---|---|
| 1 | 全站 X-Robots-Tag: noindex |
curl -I https://wait4x.online/ 与文章页均带该头;源=/etc/nginx/snippets/esa-origin-ssl.conf:11(add_header X-Robots-Tag noindex always;),博客 server 块(sites-enabled/default:92 wait4x.online→18090)include 了这个给内部服务(api/oj/token/fc/latex/cpa)设计的 snippet |
Lighthouse is-crawlable fail(重权重);搜索引擎视角全站不可索引 |
| 2 | robots.txt 不存在 | 生产 404(nginx);public/ 与 dist/ 均无 |
Lighthouse robots 审计扣分;无 Sitemap 入口 |
| 3 | en 页 hreflang 自指双 en | 生产 HTML:hreflang="en" href="…/en/en/archives/mian-sha/"(实测 404);源=src/lib/locale.ts 的 localePath('/en/…','en') 未剥旧前缀,BaseLayout.astro:91 直接调用 |
Lighthouse hreflang fail;每页必扣 |
次级问题:④无自指 canonical,且 /en/archives/mian-sha(Header nav-lang 的 href)与 /en/archives/mian-sha/(sitemap/hreflang 形状)双 200 不重定向(nginx try_files 直出),重复内容风险;⑤home <title>wait4x</title> 过薄;⑥ESA 对 text/html 缓存 2592000s(30 天)(X-Swift-CacheTime),当前靠 Last-Modified/ETag 回源重验证拿新内容(实测 Last-Modified=当日部署时刻),但响应头(含 noindex)固化在缓存对象里——修复后不 purge 则一个月内爬虫仍见 noindex。本地曾 100 的原因:测试床无 nginx snippet、无 ESA、robots.txt 404 在旧版 Lighthouse 不判 fail。
修法(A 卡片):① snippet 剥离 noindex 行,6 个内部服务 vhost 各自 server 块补回(它们确实该 noindex),博客 vhost 不加;博客私有路径(/admin/、/draft/)单独 location 加 noindex;② public/robots.txt(Allow 全站,Disallow /admin/ /draft/,Sitemap 指向 sitemap-index.xml);③ localePath 改为先 normalize 到 zh 再拼目标前缀;④ BaseLayout 加自指 canonical(Astro.site + withSlash(rawPath)),Header nav-lang href 补尾斜杠;⑤ ESA 控制台对 wait4x.online 执行一次全站 purge,并评估 HTML 边缘 TTL 调至 ≤1h 或接 purge API(发布可见性保险)。
4.2 /archives/ 归档现状(v1 #8 复核)
实测:/archives/ 全量单页,zh 6 条 en 6 条,年份分组+三轨分节(PostList.astro),无分页;content/posts 7 文,差 1 = media-sample(hidden tag,archives/index.astro 过滤条件 !data.draft && !data.tags.includes('hidden'),注释声明"视觉测试完成后应删除")。结论:达标,零改动;唯一尾单:视觉验收完成后删 media-sample(它仍占 sitemap 一条 URL)。
4.3 Artalk 评论数 API(列表页前置数据源,已实测)
- 形状:
GET /api/v2/comments?page_key=/archives/<slug>/&type=page&limit=0&site_name=wait4x.online→{"comments":[],"count":0,"roots_count":0,"page":{…,"pv":4,…}}。注意参数是site_name不是site(site报 err_no_site)。匿名可读,无需管理员。 - site 值来源:
~/docker_apps/artalk/data/artalk.ymlsite_default: wait4x.online;前端 ArtalkComments.astro 的 pv POST 已带site_name,pageKey 口径一致(/archives/<id>/,中英共用不分裂)。 - 构建期直拉可行:构建机=Artalk 宿主(同机 127.0.0.1:13030),绕开 ESA/nginx,零缓存语义问题;构建产物静态渲染数字,接受"构建时刻快照"陈旧(v1 已定此取舍)。
- 最新评论流(首页"最新心跳"旁):同端点
type=all时仍要求 page_key,全站维度改用GET /api/v2/comments?type=all&site_name=…&limit=5需带任一 page_key 的坑已遇("Page_key必须填写")——实施时以管理员 token 走/api/v2/pages(需登录,need_login:true实测)或退回逐页轮询 count 取 top-N,两路都写在卡片验收里。 - 上游健康:artalk-go 2.10.0(在跑)→ npm artalk 2.10.1(2026-10-25 发);artalk.org 域名易主(§3-7),文档引用改 artalk.js.org。
4.4 reader 纯文本模式落点(html.reader 单 class 方案)
Body 结构(BaseLayout.astro):.bg-glow(背景辉光)→ .skip-link → header.site-header.safe-area(含 nav-actions 三钮)→ main#main.container(正文+.toc侧栏+.pn上下篇+#artalk-container)→ footer.site-footer。会被覆盖/剥离的选择器清单(global.css + 组件 scoped):
- 隐藏:
.bg-glow、.read-progress(顶进度条)、Header.nav-actions(保留品牌+导航词)或整个.site-header收为一行、Footer 收为备案单行(ICP 陕ICP备2026014860号-1 不可隐——合规底线); - 中性化:正文入场动画类(global.css 动效层
prefers-reduced-motion已有的降级规则可复用同款写法)、列表微浮 hover、.atk-pv-line/#artalk-container隐藏或保留(建议保留评论——reader 是去装饰不是去内容,antfu Plaintext 同款语义); - 增强:
.prose-reading/.prose-tech字号微升一档、行宽略收(tokens.css 变量覆写)。 - 入口:CommandPalette
data-cmd="reader"(照data-cmd="theme"模式,src/components/CommandPalette.astro:42)+ 键盘r(Keyboard.astro 弦位表)+ localStorage 持久化;VT 软导航下 class 挂documentElement天然存活。
5. 实施方案卡片
A|SEO 解封三件套 + ESA purge(工作量 1d;风险:nginx 重载失误→保留 .bak 回滚,ESA purge 不可逆但无害)
- 目标:搜索引擎可索引,Lighthouse SEO ≥95。
- 做法:
/etc/nginx/snippets/esa-origin-ssl.conf删 noindex 行;api/oj/token/fc/latex/cpa/git各 vhost server 块补add_header X-Robots-Tag noindex always;;博客 vhost 加location /admin/ { add_header X-Robots-Tag noindex always; };public/robots.txt新建;ESA 全站 purge + HTML TTL 评估 ≤1h。 - 验收:
curl -sI https://wait4x.online/ | grep -ci x-robots-tag= 0;curl -s https://wait4x.online/robots.txt含Sitemap: https://wait4x.online/sitemap-index.xml;curl -sI https://wait4x.online/admin/ | grep -ci noindex= 1;Lighthouse 生产 home SEO ≥95。
B|localePath 双 en + canonical + 尾斜杠(0.5d;风险低,纯前端)
- 做法:
src/lib/locale.tslocalePath 先归一到 zh 路径再拼;BaseLayout.astro加<link rel="canonical" href={new URL(withSlash(rawPath), Astro.site)}>;Header nav-lang href 与所有站内链接统一带尾斜杠。 - 验收:
grep -c '/en/en/' dist/en/archives/mian-sha/index.html= 0;dist/内每页有自指 canonical;playwrightlink[hreflang="en"]的 href 与自身 URL 相等;curl -sI https://wait4x.online/en/archives/mian-sha(无斜杠)→ 301 或 canonical 唯一。
C|构建期内容 lint + 生产冒烟(1d;风险:lint 误报阻断发布→先 warn 一周再 fail)
- 做法:
scripts/build-perf/content-lint.mjs(断链:a href 站内前缀逐一对 dist 产物;图片存在性;frontmatter typebox schema;zh/en 配对警告);build.sh守卫挂钩[ -f scripts/build-perf/content-lint.mjs ] && node … || echo skip(铁律:存在性守卫必须是第一笔改动);生产冒烟脚本 curl robots/sitemap/首页头三断言。 - 验收:人为引入断链 md → build 输出 FAIL 清单;正常仓 build 通过;
sh infra/deploy/build.sh全链绿。
D|/draft/ 预览路由(1d;风险:草稿 URL 泄露→长随机段+noindex+不入 sitemap)
- 做法:posts 集合 frontmatter 加
draft: boolean;src/pages/draft/[slug].astro(draft:true 文章构建进/draft/<token>/<slug>/,token=构建期环境变量注入的随机串);getStaticPaths 正式路由已过滤 draft(!data.draft现成);robots.txt Disallow /draft/;nginx 无需改(静态目录直出)。 - 验收:draft 文章不出现在
/archives/与 rss.xml/sitemap;/draft/<token>/<slug>/200;curl -sI …/draft/ | grep -ci noindex= 1;playwright 断言 draft 页无 nav 中"文章"aria-current。
E|reader 纯文本模式(0.5d;风险:覆盖不全→按 §4.4 清单逐条断言)
- 做法:
html.reader单 class(global.css 尾部集中一段,全部html.reader xxx前缀);CommandPalette 加data-cmd="reader"词条(i18n/ui 双语);Keyboardr单键;localStoragereader持久化。 - 验收:playwright 触发命令后
.bg-glow/.read-progress不可见、备案号可见、正文段落数不变;html有readerclass 且刷新(reload)后仍在;E2E zh/en 各跑一遍。
F|列表评论数 + 阅读时长角标(1d;风险:Artalk 不可用时构建卡死→超时 3s 降级 –,lint warn 不 fail)
- 做法:
scripts/build-perf/artalk-counts.mjs构建期对每篇GET 127.0.0.1:13030/api/v2/comments?…&site_name=wait4x.online&limit=0取 count 写dist内联进 props(或 src/data/ 快照 JSON,构建前生成);PostList.astro li 加<span class="cnt">N</span>与阅读时长角标(复用[...slug].astro:39的汉字/400 算法抽成 lib);首页"最近心跳"旁"最新评论"流(§4.3 两路择一)。 - 验收:构建日志含每篇 count 拉取;dist 列表 HTML 含
class="cnt";断 Artalk(停容器 30s)build 仍成功且角标–;playwright 列表页可见"N 条"与"~8 min"。
G|gallery EXIF 元数据卡(1d;风险:老图无 EXIF→字段缺省隐藏不渲染空行)
- 做法:photos_ingest.py 产物已含 exifr 数据,确认 JSON 字段(机型/焦段/光圈/ISO/时间/地点)→ gallery 详情/灯箱下加等宽字体表(mono,ink-3);nbfox 式"元数据即说明"。
- 验收:任一有 EXIF 的图渲染 6 字段中 ≥4;无 EXIF 图无空表壳;E2E 断言 mono 类名。
H|home title/description 语义化 + RSS 可见性(0.5d)
- 做法:home
<title>wait4x · 阅读 技术 摄影</title>级别语义;/archives/顶部加一行 RSS 提示(xeiaso 式,链 /rss.xml 与 /en/rss.xml);description 按页级注入(BaseLayout 已有 prop,逐页补实)。 - 验收:playwright 断言每类页 title 唯一;archives 页含 rss 链接且 hreflang 正确。
I|瞬间编号化 + 友链页(各 0.5d)
- I1 moments 每条构建期序号
#N(diygod/qh1009/阮一峰三方验证的节奏感)+ 页顶"本周瞬间"聚合块(可选)。 - I2
src/pages/links.astro+content/links.yaml(name/url/desc/avatar),导航不加项(克制),入口放 about 与页脚。验收:links 页渲染全部条目且 a[href] 全 200(lint 断链覆盖)。
J|偏好雏形 + craft 编年页(观望):reader/辉光/动效三 toggle 收进命令面板 settings 分组(不做独立面板 UI);terminal 页扩"工艺案例编年体"(rauno /craft 式)列为远期。邮件复制微交互(rauno "Copied")0.2d 可顺手做进 Footer。
6. 排期建议(三批)
- 立即(本周,SEO 解封是硬闸门):A → B → C(C 的生产冒烟依赖 A/B 上线)→ E;ESA purge 随 A 同日执行。依赖:A 需 homelab nginx 操作权限(用户或运维车道);ESA 控制台 purge 需用户操作单。
- 本月:D(draft 路由)→ F(评论数,依赖 Artalk 在线策略确认)→ G(EXIF)→ H;尾单:删 media-sample。
- 观望(触发条件):I1/I2(内容节奏成型后)、J(terminal 页改版时合并)、Artalk 2.10.1 升级(下个维护窗口)、Newsletter(RSS 订阅量证明需求后)、GitHub PAT(热力图真实数据,用户素材依赖,scratchpad 在案)。
- 用户操作单(非代码):① ESA 全站 purge + HTML TTL 调整 + /artalk/api 绕缓存规则复核;② GitHub PAT(热力图);③ nginx 重载窗口确认。
7. 明确不做的(与灰阶克制冲突,v1 P2 续封 + 新增)
- 背景音乐/一言/背景特效(v1 P2,innei 同款):稀释终端隐喻一致性。
- 首页大图专题卡/瀑布流重化(v1 P2,nbfox 同款):内容电商型视觉,与"灰阶骨架×分轨正文"定稿相悖。
- 常驻浮动 TOC/阅读进度大改(v1 P2):现 .toc 桌面 sticky 已够,长文少。
- 新增:评论数实时化/SWR(构建期快照已够,实时=引入运行时查询+ESA 缓存语义复杂度)。
- 新增:AI persona 注入彩蛋进正式页(diygod 同款虽有趣,但正式内容层注 prompt 有被搜索引擎误读风险——只进 terminal 彩蛋页)。
- 新增:独立设置面板 UI(innei 式面板):命令面板分组已覆盖收纳需求,独立面板是 UI 负担。
附:本轮实测命令与产物索引
- 生产:
curl -sI https://wait4x.online/{,archives/mian-sha/,robots.txt,admin/}(noindex 头、404、30 天缓存头);/sitemap-0.xml34 URL 全 200。 - 本机:
/etc/nginx/snippets/esa-origin-ssl.conf、sites-enabled/default:92、docker_apps/artalk/data/artalk.yml、127.0.0.1:13030/api/v2/comments?…响应原文。 - 外站快照:/tmp/v2/*.html(会话级):rauno.me(含 /craft /projects)、diygod.cc(含 /posts)、xeiaso.net(含 /blog)、shud.in、vincentwill.com、sabrinacodes.com、artalk.org(易主证据);brianlovin.com=Vercel 挑战页(失败标注)。
- 仓库:BaseLayout.astro / locale.ts / PostList.astro / CommandPalette.astro / ArtalkComments.astro / [slug] 与 [...slug].astro / archives/index.astro / build.sh / global.css / tokens.css。