静态 SEO
审计并改进静态 HTML 网站的 SEO 设置,涵盖九个类别——头部元数据、结构化数据、内容质量、Open Graph 图像、站点地图与索引、Agent 发现、性能、重定向和 CI 验证。配方是平台中立的:原始 <meta> 标签、原始 JSON-LD、手动编写的 sitemap.xml、通用 CI 工具。审计框架与 astro-seo 类似,但缺少 @jdevalk/astro-seo-graph 主干。
代码配方位于 AGENTS.md 中——当你需要实施特定修复时请阅读该文件。本文件包含工作流程和审计检查清单。
工作流程
- 检测项目——确认这是一个静态站点,识别构建工具,找到应用更改的位置。
- 审计——对九个类别进行评分并生成可操作的发现。
- 改进——生成或修改文件以缩小差距。配方位于
AGENTS.md。 - 元数据检查——对技能生成的每个短字符串(标题、描述、schema
description字段、FAQ 答案)调用metadata-check。 - 验证——运行任何构建,验证输出,提醒用户非文件性任务(Search Console、Bing Webmaster Tools、IndexNow 密钥提交)。
阶段 0: 检测项目
在审计前确认基本信息:
- 它确实是一个静态站点。 寻找已构建的 HTML——仓库根目录下的
index.html,或者位于_site/(Jekyll)、public/(Hugo / 11ty / Gatsby)、dist/(Vite / Astro 静态)、out/(Next.js 带output: export) 下。如果所有内容都是服务器端渲染的(Express、PHP、动态路由),那么这个技能是错误的——如果是 Astro 请指向astro-seo,如果是 WP 插件页面请指向wp-readme-optimizer,或者推荐通用的 SEO 审计。 - 源构建工具。 决定了应用头部元数据更改的位置:
_config.yml/_layouts/→ Jekyllconfig.toml/config.yaml/themes/→ Hugo.eleventy.js/_includes/→ 11tygatsby-config.js/src/components/SEO.*→ Gatsbynext.config.js带output: 'export'和pages/_document.tsx→ Next.js 静态导出astro.config.mjs→ Astro(这种情况下请使用astro-seo替代)- 没有构建配置,只有 HTML 文件 → 手动编写或抓取(例如
wp-static-clone输出)。直接编辑 HTML 或使用后处理脚本。
- 规范站点 URL。 在仓库中搜索生产环境源——通常在
_config.yml、config.toml、astro.config中,或硬编码在布局中。如果缺失、为空或为localhost,请将其标记为阻塞性问题,然后再进行任何其他操作。 规范标签、站点地图、OG 图像 URL 和 JSON-LD@id值都基于此。 - 部署目标。 读取
vercel.json、netlify.toml、wrangler.toml或public/_headers以确定主机。影响阶段 2 中的重定向和头部语法。 - 站点是否多语言? 检查语言环境子目录(
/en/、/nl/、/de/)或构建工具的 i18n 配置。如果是,则 hreflang 很重要;如果不是,则跳过。 <head>中已经有什么? 打开一个已构建的 HTML 文件并盘点:标题、描述、规范标签、robots、Open Graph、Twitter 卡片、JSON-LD、hreflang。如果能引用已有的内容,阶段 1 中的审计会更快。
只询问你无法检测到的内容。
阶段 1: 审计
每个类别满分 10 分。对于每个类别,给出 2–4 个具体发现,并引用实际的 HTML、配置或模板。在每个类别中,检查分为不同层级:
- 必须——发布阻塞项。失败会导致可见的 SEO 倒退。
- 应该——标准做法。跳过会损害覆盖率。
- 锦上添花——前瞻性或情境性。有用但不是每个站点的基础。
对于小型个人站点,除非用户要求全面处理,否则跳过锦上添花检查。
1. 头部元数据 (/10)
- 必须——每个页面都有
<title>和<meta name="description">。 - 必须——设置
<link rel="canonical">,去除跟踪参数,源自生产环境源。 - 必须——当页面为
noindex时省略规范标签(根据 Google 的建议)。 - 必须——
<title>长度 30–65 个字符,<meta name="description">长度 70–200 个字符(SERP 截断边界;与metadata-check默认值相同)。 - 应该——
<meta name="robots">包含max-snippet:-1、max-image-preview:large、max-video-preview:-1。 - 应该——每个页面上都有 Open Graph(
og:title、og:description、og:image、og:url、og:type、og:site_name)。 - 应该——当 Twitter Card 标签(
twitter:card)与 Open Graph 重复时抑制(Twitter 会自动回退)。 - 应该——多语言站点上的
hreflang备用链接。如果是单语言则跳过。 - 应该——每个页面只有一个
<meta name="robots">和一个og:image(旧工具有时会发出重复项)。
2. 结构化数据 / JSON-LD (/10)
- 必须——每个重要页面上至少有一个
<script type="application/ld+json">块。 - 应该——使用链式
@graph而不是扁平的Article对象——实体通过@id引用连接,以便BlogPosting可以指向其Person作者和WebPage父级。 - 应该——在相关位置显示
WebSite、Blog/WebPage、Person/Organization、BlogPosting/Article、BreadcrumbList、ImageObject。 - 应该——信任信号:
publishingPrinciples、copyrightHolder、copyrightYear、knowsAbout、SearchAction。 - 必须——通过 Rich Results Test 和 ClassySchema 验证。
3. 内容质量 (/10)
- 必须——每个页面都有唯一的
<title>和<meta name="description">(整个站点没有重复的元数据)。 - 必须——每个页面只有一个
<h1>。 - 应该——通过
metadata-check(阶段 2.5)审计<title>和<meta name="description">,检查前置加载、具体性和 SERP 适配度。 - 应该——通过
readability-check审计单篇长文的内容正文(不要批量审计)。 - 应该——每个
<img>都有alt属性(或用于装饰性图片的alt=""/role="presentation")。 - 应该——内部链接使用根相对路径(
/foo/)而不是绝对路径(https://...)——在域名更改和预览中也能正常工作。
4. Open Graph 图像 (/10)
- 必须——每个页面都有 OG 图像。
- 必须——1200×675(Google Discover 最小宽度 1200px,16:9 比例)。
- 应该——JPEG(社交平台不能可靠地支持 OG 的 WebP / AVIF)。
- 应该——在构建时生成(satori-cli、sharp、ImageMagick、Vercel OG、Bannerbear),而不是手动为每个页面上传——防止漂移。
- 应该——URL 由 slug 确定性派生(例如
/og/<slug>.jpg),这样添加页面会自动获得图像。 - 应该——正文内容中的每个
<img>都有alt属性(或alt=""/role="presentation")。通过html-proofer或类似工具在 CI 中验证。
5. 站点地图与索引 (/10)
- 必须——
/sitemap.xml(或用于分割站点地图的/sitemap_index.xml)可访问,有效的 XML,每个 URL 返回 200。 - 必须——站点根目录存在
robots.txt并引用站点地图。 - 必须——存在 RSS 源,通过
<link rel="alternate" type="application/rss+xml">广告,包含完整文章内容(非截断摘要)。 - 应该——如果站点有多个内容类型(
sitemap-posts.xml、sitemap-pages.xml),则按部分分割——在 GSC 中调试索引更容易。 - 应该——
<lastmod>从 git 提交时间戳(最准确)、构建时间戳(可接受)或 frontmatter 日期(最后手段)填充。来自 CI checkout 的文件系统mtime是错误的——它是 checkout 日期,而不是内容日期。 - 应该——集成 IndexNow。验证密钥作为静态
/<key>.txt路由位于站点根目录,加上一个构建或部署钩子,将新 URL POST 到https://api.indexnow.org/IndexNow。基于生产主机进行门控(例如CF_PAGES_BRANCH=main、VERCEL_ENV=production、CONTEXT=production)——无条件提交会从本地构建向生产主机尚未提供服务的 URL 发送 ping,导致密钥被标记为无效(403)并强制轮换。
6. Agent 发现 (/10)
- 应该——schema 端点(
/schema/<type>.json)按内容类型公开全语料库 JSON-LD。静态 JSON 文件提交到仓库或由构建重新生成。 - 应该——schema 地图(
/schemamap.xml)列出每个 schema 端点,并在robots.txt中包含Schemamap:指令。 - 应该——站点根目录下的
llms.txt列出页面(标题 + 描述)供 LLM 消费者使用。静态文本文件;每页一行。 - 应该——markdown 备用 URL(
/blog/post.md在/blog/post/旁边)提供带有 YAML frontmatter 的干净 markdown,以便 AI 代理无需 HTML 解析即可消费内容。要么提交.md兄弟文件,要么使用 Cloudflare Transform Rule +Vary: Accept进行内容协商(CF Pages 会剥离自定义 Vary 头,因此单独使用 Transform Rule 的 URL 重写——配方见AGENTS.md)。 - 应该——根据 RFC 9727 在
/.well-known/api-catalog的 API 目录,格式为application/linkset+json(RFC 9264)。列出 schema 端点、schemamap、RSS 源和任何站点特定的 API。静态 JSON 文件。 - 应该——
robots.txt中的 Content Signals 指令(Content-Signal: ai-train=yes, search=yes, ai-input=yes或您首选的策略)。一行,IETF 草案,成本低。 - 应该——
/*上的Link头部指向发现文件(站点地图、llms.txt、api-catalog、schemamap)。读取响应头部的 Agent 无需解析 HTML 即可找到它们。特定于主机(Cloudflare Pages / Netlify 上的_headers,Vercel 上的vercel.json,其他地方的服务器配置)。 - 锦上添花——
/.well-known/mcp/server-card.json处的 MCP 服务器卡片和/或/.well-known/agent-card.json处的 A2A 代理卡片。仅当站点公开 MCP 服务器或 A2A 代理时相关。 - 锦上添花——指向对话端点的
<link rel="nlweb">。NLWeb 采用尚早;此标签只有一行,值得拥有,但在 2026 年不是评分障碍。 - 锦上添花——
/.well-known/ai-catalog.json处的 ARD(Agentic Resource Discovery)目录,列出域名提供的内容(MCP 服务器、A2A 代理、OKF 包、站点特定 API)。v0.9 草案,可选——但它是 MCP / A2A 卡片和 OKF 包发挥作用的发现层。两个注意事项:基本规范(Agent-Card/ai-catalog)将媒体类型字段命名为mediaType,而 ARD 层(ards-project/ard-spec)将其命名为type——以相同的值输出两个键,以便条目在任一解读下都能验证(两个规范都要求消费者忽略未知键)。ARD 还添加了一个可选的representativeQueries数组,包含每个条目的示例提示。静态 JSON 文件。 - 锦上添花——OKF(开放知识格式)包:一棵类型化的 Markdown 概念文件树(每页一个,路径镜像规范 URL),打包为单个
.tar.gz,中间有索引文件。提供和发现是 OKF 的明确非目标——这就是 ARD 目录条目的用途。v0.9 草案,可选。尚无注册的媒体类型,因此临时字符串是application/okf-bundle+gzip(在 knowledge-catalog#111 和 ard-spec#27 中跟踪);标记为临时,可能会更改。最好从站点其余部分派生自的同一源生成,而不是手动维护的副本。
7. 性能 (/10)
- 必须——哈希资产提供
Cache-Control: public, max-age=31536000, immutable(或等效)以便仅下载一次。 - 应该——通过
<link rel="preload" as="font" crossorigin>预加载主要 Web 字体为woff2。 - 应该——
No-Vary-Search响应头部从缓存键中去除 UTM 参数(因此/?utm_source=x和/共享一个缓存条目)。 - 应该——首次绘制时没有渲染阻塞的 JavaScript(延迟或异步非关键脚本)。
- 应该——图像使用现代格式(页面内容使用 WebP / AVIF;OG 卡片仅使用 JPEG)和首屏下方的
loading="lazy"。 - 应该——所有 Lighthouse / PageSpeed Core Web Vitals 均为绿色:LCP < 2.5s、INP < 200ms、CLS < 0.1。
8. 重定向与错误处理 (/10)
- 必须——为每个曾经存在并移动过的 URL 维护
_redirects/vercel.json/ 服务器配置。 - 必须——永久移动使用
301而不是302。 - 必须——
404.html(或等效)返回 404 状态,而不是 200。使用curl -I针对故意错误的 URL 进行验证。 - 应该——在 404 页面上提供模糊匹配建议("你的意思是……?")以应对 URL 中的拼写错误。静态实现:预先构建有效 slug 的 JSON 索引,客户端进行模糊匹配。
9. CI 验证 (/10)
- 必须——CI 中的死链检查器。每次推送涉及内容时使用 linkinator 或 lychee。内部和外部链接都检查——内部链接捕获构建回归,外部链接捕获链接腐烂。安排每周运行仅检查外部链接。
- 应该——通过 html-proofer 或 W3C Validator 进行 HTML 验证——捕获破坏爬虫的错误标记。
- 应该——每次推送时运行 Lighthouse CI,并设置分数阈值(例如 SEO ≥ 95,Performance ≥ 80)。
- 应该——通过 Schema.org JSON-LD 验证器 在 CI 中进行 JSON-LD 验证(没有官方的 CLI;通过向 API 发送 POST 请求的 Node 脚本进行管道传输)。
- 应该——在 CI 中进行标题和描述长度验证:一个小脚本遍历构建的 HTML,提取
<title>和<meta name="description">,标记任何超出边界的项。