静态站的入口、索引、度量:一次体检清单
大纲 · 15 节
站里内容涨到 158 个页面(含五个同域子站)之后,我做了一次体检。结论有点刺:内容没问题,问题全在“内容之外”的三层。
这篇把体检的清单和答案记下来——任何静态站都能照着跑一遍,不需要特殊工具,只用 curl 和一台能访问自己站点的终端。
一、入口:搜索引擎能不能进来
两个必查项,都在一分钟内能验完。
1. robots.txt 真的存在吗
curl -s -o /dev/null -w "%{http_code} %{content_type}\n" https://你的站/robots.txt
期望 200 text/plain。如果返回 200 text/html,就是中招了:很多托管平台(Cloudflare Pages、Netlify 的某些配置)在没有 robots.txt 时会把未命中请求回落到首页,于是搜索引擎拿到一份“HTML 写成的 robots”。
我不想手写这个文件,因为域名会变。做法是让构建生成它(Astro 里就是一个 src/pages/robots.txt.ts 端点),域名只保留在 astro.config 一处,换域名时不会漏改第二个地方。
2. 不存在的地址返回什么
curl -s -o /dev/null -w "%{http_code}\n" https://你的站/这个路径肯定不存在/
期望 404。如果返回 200,那是“软 404”,比 404 更糟——等于对搜索引擎声明“我有无数个内容完全相同的页面”(见文末坑一)。
二、索引:内容能不能被找到
3. sitemap 覆盖了全部页面吗
数一下 sitemap 的 <loc> 条数,和站上真实页面数对比:
curl -s https://你的站/sitemap-0.xml | grep -o "<loc>" | wc -l
这里最容易漏的是同域挂载的子应用:它们通常不走主站的构建管线(我们的是预构建产物直接放进 publish/assets/),于是主站 sitemap 完全看不见它们的内页。我这次体检时,sitemap 里 99 条、真实 158 页,缺的 57 条全是子站——刚上架的 45 篇知识库对内页对搜索引擎是隐形的。
修法是让构建期扫一遍产物目录,把找到的 HTML 补进 sitemap(Astro 用 sitemap({ customPages }))。
4. 每页有 canonical / 分享卡 / 结构化数据吗
curl -s https://你的站/任意一页/ | grep -o 'rel="canonical"\|og:image\|application/ld+json' | sort | uniq -c
三样都要有:
- canonical:只取路径、丢掉查询参数(站内搜索这类
?q=状态参数最容易造成重复页面)。 - og:image:没有卡片图时,转发出去的链接是一块空白。全站一张默认图(1200×630)就够,不必逐页生成。
- JSON-LD:全站一条
WebSite,文章页加Article、作品页加CreativeWork。
5. 站内搜得到吗(用户视角)
这一项最容易被“我有个搜索框”骗过去——要分清搜的是全网还是站内。我的首页一直有一个搜索框,但它调的是联网搜索 API。内容过百页之后,站内检索是刚需。
三、度量:你有没有尺子
“提高曝光率”这句话,在没有访问数据和收录数据之前是不可验收的。我把它收窄成三条可查信号:被搜到(进收录)、被用上(RSS 订阅或子站回访)、被引用(外部链接)。
访问统计用 Cloudflare Web Analytics:Pages 项目里一键开启,beacon 由边缘注入(不在构建产物里,所以本地预览永远看不到它——别为此排查)。
站况本身不需要外部服务,构建期就能算:页面构成、每个模块的条数与最后改动、元数据完整度、站内互链、孤儿页面。这些数字做成一个页面(我们的 /console/),比任何“感觉最近没怎么写”都可靠。
四、四个真实踩过的坑
坑一:没有 404.html 的平台会全局回落
Cloudflare Pages 在缺少 404.html 时,把未命中的路径回落到根 index.html 并返回 200。它同时会盖住 _redirects 里的 200 rewrite 规则(301 不受影响)。加一张真的 404 页即终结,且不会影响同域子应用的真实静态文件(静态资源优先级最高)。
坑二:标签大小写不一致,两个平台裂出不同数量的页面
Godot 和 godot 是两个不同标签 → 两张标签页。Windows 文件系统不区分大小写,两个目录被合并成一份;Linux(CI 上)实打实生成两个。于是同一个仓库在本地和线上页面数差 1。这种差异只有把页面数写进仪表盘才看得见。
坑三:分析脚本在没有数据源时会“安静地写 0”
把本地会话分析脚本挂进 build 看起来一劳永逸,但它在找不到 ~/.codex/sessions 时不报错,而是用 0 覆盖已有的统计文件——CI 上没有那个目录,挂上去就把线上看板的数字清零了。自动化脚本必须先有“无数据源则早退、不落地”的守卫,才配进构建链。
坑四:用文件 mtime 当“最后改动时间”会在云端撒谎
CI 刚 checkout,所有文件的 mtime 都是“今天”,新鲜度灯会全绿。跨机器稳定的口径是文件自带的日期字段,其次才是该路径的 git 提交日期。
五、可复用清单
入口
-
robots.txt返回text/plain且声明 sitemap - 不存在的路径返回 404(不是 200)
索引
- sitemap 条数 ≈ 真实页面数(含同域子应用)
- 每页有 canonical(不含查询参数)
- 每页有 og:image 与 twitter 卡
- 全站有 WebSite JSON-LD,文章页有 Article
- 站内有自己的全文检索(和“全网搜索”区分开)
度量
- 访问统计已开启,且能在页面源码里搜到 beacon
- 有一张构建期算出来的站况快照(规模 / 新鲜度 / 完整度 / 互链)
- 三条外部信号有地方人肉记录:被搜到、被用上、被引用
相关
- 这次体检的过程记录:给站装一块仪表盘:曝光基本盘、站控室与站内检索
- 带出这批问题的上架记录:实验室开张:五个 Kimi 子站搬进小站
- 后端能力与免费额度:给静态站免费长出后台:Cloudflare 免费能力调研
- 站况看板:站控室 | 内容管道看板:复利工作台