Use Cases (更新: 2026/6/2)

用 Claude Code 实现 RSS Feed:静态站点 RSS 2.0 与 Atom 实战

用 Claude Code 生成 RSS 2.0/Atom,处理 XML 转义、日期、绝对 URL、多语言、验证与缓存。

用 Claude Code 实现 RSS Feed:静态站点 RSS 2.0 与 Atom 实战

RSS 仍然是技术内容的稳定入口

发布文章不等于读者一定会看到。搜索、社交平台、邮件、Slack、RSS 阅读器都会影响传播。RSS feed 是一个机器可读的 XML 文件,用来列出文章标题、链接、摘要、发布时间和分类。它不像社交平台那样依赖算法排序,对开发者、研究员、编辑和内部知识库仍然很实用。

XML 的规则比普通 HTML 更严格。标题里一个没有转义的 & 就可能让整个 feed 失效。Atom 是另一种订阅格式,由 RFC 4287 定义。初学者可以先实现 RSS 2.0,再按需求补 Atom。

本文用 Claude Code 实现静态站点 feed,但不会只写“让 AI 生成 RSS”。我们会处理 RSS 2.0、Atom、XML 转义、日期格式、绝对 URL、多语言 feed、验证、缓存,以及给 Claude Code 的审查提示词。相关内容可继续阅读 Claude Code 博客 CMSClaude Code SEO 优化Claude Code sitemap 生成

实现时以一次资料为准:RSS 2.0 看 RSS Advisory Board 规范,Atom 看 IETF RFC 4287,验证用 W3C Feed Validation Service,Astro 项目看 Astro RSS recipe

三个真实使用场景

第一个场景是技术博客的复访。很多高级读者会把常读网站加入 Feedly、Inoreader 或自建阅读器。只要 feed 正常,新文章就会进入他们的阅读流程,而不是依赖某条社交动态是否被看到。

第二个场景是公司内部知识更新。发布说明、事故复盘、安全公告、架构决策记录都可以共用一个 feed。Slack bot、内部门户、状态页读取同一份 XML,作者只维护一份文章数据。

第三个场景是多语言 SEO。一个站点如果同时有中文、日文、英文、西班牙文等内容,就不应该只提供一个混合 feed。/zh/rss.xml 应只包含中文文章,/en/rss.xml 应只包含英文文章。collection、URL 前缀和 language 必须一致。

第四个场景是商业转化。ClaudeCodeLab 的文章会连接到模板、产品、培训和咨询。如果新文章没有进入 RSS,老读者就少一个触点。Claude Code 培训与咨询 这样的 CTA 应该作为自然下一步出现,而不是硬插广告。

先写清楚 feed 契约

在让 Claude Code 修改代码前,先决定规则。很多问题都来自需求太模糊:相对 URL、草稿泄露、XML 损坏、日期排序错误、不同语言混在一起。

项目推荐做法原因
格式先 RSS 2.0,必要时加 Atom支持广,实现简单
URL全部使用绝对 URL外部阅读器才能稳定打开
日期RSS 用 toUTCString(),Atom 用 toISOString()更接近常见规范格式
内容先输出 description全文 HTML 需要 sanitize 和图片 URL 处理
数量20 到 50 篇避免 feed 过大
缓存设置明确缓存策略发布后不会长时间看不到更新
验证本地脚本加 W3C Validator浏览器能打开不代表规范正确

RSS 2.0 的核心是 channelitemchannel 描述站点,item 描述每篇文章。guid 用来稳定识别文章,通常可以使用文章永久链接。

无依赖 RSS 生成脚本

下面的脚本保存为 scripts/generate-rss.mjs,执行 node scripts/generate-rss.mjs 后会生成 dist/rss.xml。真实项目中只需要把 posts 替换为 MDX 或 CMS 数据。

// scripts/generate-rss.mjs
import fs from "node:fs";
import path from "node:path";

const siteUrl = "https://example.com";
const outputPath = path.join(process.cwd(), "dist", "rss.xml");

const posts = [
  {
    title: "用 Claude Code 实现 RSS Feed",
    description: "为静态站点生成并验证 RSS 2.0 feed。",
    slug: "claude-code-rss-feed",
    pubDate: "2026-06-02T09:00:00+09:00",
    tags: ["Claude Code", "RSS"],
  },
];

function escapeXml(value) {
  return String(value ?? "")
    .replace(/&/g, "&")
    .replace(/</g, "&lt;")
    .replace(/>/g, "&gt;")
    .replace(/"/g, "&quot;")
    .replace(/'/g, "&apos;");
}

function toRssDate(value) {
  const date = new Date(value);
  if (Number.isNaN(date.getTime())) throw new Error(`Invalid date: ${value}`);
  return date.toUTCString();
}

const items = posts.map((post) => {
  const url = new URL(`/zh/blog/${post.slug}/`, siteUrl).toString();
  return `    <item>
      <title>${escapeXml(post.title)}</title>
      <link>${url}</link>
      <guid isPermaLink="true">${url}</guid>
      <description>${escapeXml(post.description)}</description>
      <pubDate>${toRssDate(post.pubDate)}</pubDate>
    </item>`;
}).join("\n");

const xml = `<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>ClaudeCodeLab 中文</title>
    <link>${siteUrl}/zh/</link>
    <description>Claude Code 实战教程与工作流</description>
    <language>zh</language>
    <lastBuildDate>${new Date().toUTCString()}</lastBuildDate>
    <ttl>60</ttl>
${items}
  </channel>
</rss>
`;

fs.mkdirSync(path.dirname(outputPath), { recursive: true });
fs.writeFileSync(outputPath, xml, "utf8");
console.log(`Generated ${outputPath}`);

这里最重要的是 escapeXml()new URL() 和日期校验。Claude Code 重构时不能删掉这些保护。

Astro 项目的实现

Astro 项目可以使用官方的 @astrojs/rss。先确认 astro.config.mjs 中设置了 site

npm install @astrojs/rss
// src/pages/zh/rss.xml.ts
import rss from "@astrojs/rss";
import { getCollection } from "astro:content";

export async function GET(context: { site: URL }) {
  const posts = await getCollection("blog-zh", ({ data }) => !data.draft);

  const items = posts
    .sort((a, b) => {
      const aDate = new Date(a.data.updatedDate ?? a.data.pubDate).getTime();
      const bDate = new Date(b.data.updatedDate ?? b.data.pubDate).getTime();
      return bDate - aDate;
    })
    .slice(0, 30)
    .map((post) => ({
      title: post.data.title,
      description: post.data.description,
      pubDate: post.data.updatedDate ?? post.data.pubDate,
      link: `/zh/blog/${post.id}/`,
      categories: post.data.tags,
    }));

  return rss({
    title: "ClaudeCodeLab 中文",
    description: "Claude Code 实战教程与工作流",
    site: context.site,
    items,
    customData: "<language>zh</language><ttl>60</ttl>",
  });
}

在页面布局的 head 中加入自动发现链接:

<link rel="alternate" type="application/rss+xml" title="ClaudeCodeLab RSS" href="/zh/rss.xml" />
<link rel="alternate" type="application/atom+xml" title="ClaudeCodeLab Atom" href="/zh/atom.xml" />

全文 RSS 可以做,但需要处理 HTML sanitize、相对图片、组件和广告脚本。初版建议只放 description,稳定后再扩展。

Atom、多语言与验证

Atom 的 idupdated 要稳定,日期用 ISO 字符串更简单。

function atomEntry(post, siteUrl) {
  const url = new URL(`/zh/blog/${post.slug}/`, siteUrl).toString();
  return `  <entry>
    <title>${escapeXml(post.title)}</title>
    <link href="${url}" />
    <id>${url}</id>
    <updated>${new Date(post.pubDate).toISOString()}</updated>
    <summary>${escapeXml(post.description)}</summary>
  </entry>`;
}

多语言 feed 要把 collection、prefix、language 绑定在一起:

const feeds = [
  { collection: "blog", prefix: "", language: "ja", title: "ClaudeCodeLab" },
  { collection: "blog-en", prefix: "/en", language: "en", title: "ClaudeCodeLab English" },
  { collection: "blog-zh", prefix: "/zh", language: "zh", title: "ClaudeCodeLab 中文" },
];

本地验证脚本可以先挡住明显错误:

// scripts/check-feed.mjs
const feedUrl = process.argv[2] ?? "http://localhost:4321/zh/rss.xml";
const response = await fetch(feedUrl);
const xml = await response.text();
const failures = [];

if (!response.ok) failures.push(`HTTP status is ${response.status}`);
if (!xml.includes("<rss")) failures.push("missing rss root");
if (!xml.includes("<channel>")) failures.push("missing channel");
if (!xml.includes("<item>")) failures.push("missing item");
if (/&(?!amp;|lt;|gt;|quot;|apos;|#\d+;|#x[a-fA-F0-9]+;)/.test(xml)) failures.push("unescaped ampersand");
if (!/<guid[^>]*>https?:\/\//.test(xml)) failures.push("guid should be absolute");

if (failures.length) {
  console.error(failures.map((failure) => `- ${failure}`).join("\n"));
  process.exit(1);
}

console.log(`OK: ${feedUrl}`);

常见失败包括:R&D 没有转义导致 XML 失效;草稿文章进入 feed;相对 URL 在外部阅读器中打不开;日期格式模糊导致排序异常;中文 feed 链接到英文页面;CDN 缓存太久导致发布后看不到更新。这些都应该写进 Claude Code 的 review 条件。

Claude Code 提示词与实际验证

实现提示词可以这样写:

为 Astro 静态站点实现 RSS 2.0。
- 只编辑 src/pages/zh/rss.xml.ts。
- 使用 @astrojs/rss。
- 排除 draft。
- 按 updatedDate 或 pubDate 从新到旧排序。
- 限制 30 篇。
- 使用正确的 /zh/blog/ URL 前缀。
- 加入 language 和 ttl。
- 最后报告验证命令和结果。

审查提示词要更批判:

请批判性审查 RSS 实现。
优先检查 XML 转义、相对 URL、draft 泄露、日期格式、guid 稳定性、多语言 URL 前缀、缓存和 W3C 验证风险。

我在一个小型 Astro 数据集上试过这套流程。本地脚本能抓到没有转义的 & 和缺失的绝对 guid,W3C Feed Validator 能补充格式检查。人工仍然要看翻译是否自然、CTA 是否匹配读者意图,以及 feed 是否真的出现在阅读器中。团队如果要把 RSS、sitemap、文章 QA 和商业转化串起来,可以从 Claude Code 培训与咨询 开始。

#Claude Code #RSS #Atom #Astro #静态站点
免费

免费 PDF: Claude Code 速查表

输入邮箱即可获取一页 PDF,整理常用命令、审查习惯和安全工作流。

我们会妥善保护你的信息,不发送垃圾邮件。

把 Claude Code 变成真正能带来结果的工作流

先领取中文说明的免费 PDF,再进入英文商品页选择合适的教材。如果你需要团队落地、流程设计或内容变现支持,也可以直接咨询。

Masa

关于作者

Masa

专注 Claude Code 实务流程、团队导入和内容转化的工程师。