首页 / Astro 教程 / RSS 输出

Astro 教程

RSS 输出

本教程共 56 篇 · 第 48 篇 · 更新于 2026-08-07 · 约 10 分钟阅读

AstroAstro 教程RSS订阅源端点内容集合@astrojs/rssfeed

本节目标:学会用官方集成 @astrojs/rss 给你的内容站生成一个 RSS 订阅源,让读者用阅读器订阅更新,并掌握从内容集合批量生成条目的做法。

如果你做的是博客、资讯类网站,读者不一定天天来刷。RSS 就是一种「读者订阅后,你发新文他自动收到」的机制。这一章讲 Astro 怎么生成 RSS feed(订阅源)。

RSS 是什么

RSS 是一份固定格式的 XML 文件,里面列出你网站近期的文章标题、链接、摘要和发布时间。读者把这份文件的地址(比如 yoursite.com/rss.xml)放进 RSS 阅读器,阅读器就会定期来取,有新内容就提醒读者。

对内容站来说,RSS 是低成本留住核心读者的好办法。Astro 提供了官方集成 @astrojs/rss 来自动生成它,不用你手写 XML。

安装 @astrojs/rss

用你习惯的包管理器装这个包:

npm install @astrojs/rss

装好后,不需要在 astro.config.mjs 里注册什么集成——它是通过「端点」来工作的(端点我们在第 34 章讲过,就是一个返回响应的特殊文件)。

创建一个 RSS 端点

src/pages/ 目录下新建一个文件,名字随意,但扩展名要用 .xml.js(或 .xml.ts),因为它决定输出 URL 是 /rss.xml。常见名字是 rss.xml.jsfeed.xml.js

下面是一个最小可用版本:

// src/pages/rss.xml.js
import rss from '@astrojs/rss';

export function GET(context) {
  return rss({
    // 输出 XML 里的 <title>
    title: 'Buzz 的博客',
    // 输出 XML 里的 <description>
    description: '一位谦虚宇航员通往星辰的指南',
    // 从端点上下文拿到你在配置里填的 site
    site: context.site,
    // 条目数组,先空着
    items: [],
    // 可选:注入自定义 XML,比如语言
    customData: `<language>zh-cn</language>`,
  });
}

这里有个关键点:site 来自 context.site,也就是你在 astro.config.mjs 里配置的 site 字段(必须填,且以 http://https:// 开头)。没填 site,RSS 里的链接就会是错的。所以请先确认配置里有 site

items 字段:订阅源的内容

RSS 真正有用的是 items 数组,每一项对应一篇文章。一个条目常用的字段有:

  • title:文章标题。
  • description:摘要或节选。
  • link:文章原始链接(URL)。
  • pubDate:发布时间。
  • content:文章完整正文(可选,支持 HTML)。

获取这些条目数据有两种主流方式:从内容集合取,或从页面文件用 glob 取。

配合内容集合生成条目

如果你用内容集合(第 20、21 章讲过,v5+ 用 src/content.config.ts + 加载器)管理文章,那 RSS 几乎是顺手的事。用 getCollection() 取出集合,再 map 成 RSS 条目:

// src/pages/rss.xml.js
import rss from '@astrojs/rss';
import { getCollection } from 'astro:content';

export async function GET(context) {
  const blog = await getCollection('blog');
  return rss({
    title: 'Buzz 的博客',
    description: '一位谦虚宇航员通往星辰的指南',
    site: context.site,
    items: blog.map((post) => ({
      title: post.data.title,
      pubDate: post.data.pubDate,
      description: post.data.description,
      // 用文章的 id 拼出链接,假设路由是 /blog/[id]
      link: `/blog/${post.id}/`,
    })),
  });
}

注意 link 需要你自己拼。上面假设每篇文章渲染成 /blog/<id>/ 路由,你要按自己实际的路由规则来写。

为了省心,官方还提供一个 rssSchema,可以直接套在内容集合的 schema 上,强制每篇都含 RSS 需要的字段:

// src/content.config.ts
import { defineCollection } from 'astro:content';
import { rssSchema } from '@astrojs/rss';

const blog = defineCollection({
  schema: rssSchema,
});

export const collections = { blog };

用了 rssSchema,你的文章 frontmatter 就得带上 titledescriptionpubDate 等,少填会在构建时报错,反而帮你提前发现问题。

用 glob 导入页面文件

如果你的文章是 src/pages/ 下的 .md/.mdx 文件(没用内容集合),可以用 pagesGlobToRssItems() 辅助函数:

// src/pages/rss.xml.js
import rss, { pagesGlobToRssItems } from '@astrojs/rss';

export async function GET(context) {
  return rss({
    title: 'Buzz 的博客',
    description: '一位谦虚宇航员通往星辰的指南',
    site: context.site,
    items: await pagesGlobToRssItems(
      import.meta.glob('./blog/*.{md,mdx}'),
    ),
  });
}

它接受 import.meta.glob 的结果,自动把每个页面的 frontmatter 转成 RSS 条目。比手写 map 省事,但前提是你的 md 文件 frontmatter 里有合规的 titledescription 等。

输出完整正文

默认 RSS 只放摘要。想让读者在阅读器里直接看全文,给条目加 content 字段,值是文章的 HTML。

用内容集合时,借助 Markdown 解析器(如 markdown-it)渲染正文,再 sanitize(清理)一遍:

// src/pages/rss.xml.js
import rss from '@astrojs/rss';
import { getCollection } from 'astro:content';
import sanitizeHtml from 'sanitize-html';
import MarkdownIt from 'markdown-it';

const parser = new MarkdownIt();

export async function GET(context) {
  const blog = await getCollection('blog');
  return rss({
    title: 'Buzz 的博客',
    description: '一位谦虚宇航员通往星辰的指南',
    site: context.site,
    items: blog.map((post) => ({
      link: `/blog/${post.id}/`,
      content: sanitizeHtml(parser.render(post.body), {
        allowedTags: sanitizeHtml.defaults.allowedTags.concat(['img']),
      }),
      ...post.data,
    })),
  });
}

这里要小心图片和相对链接:RSS 阅读器里相对路径图片可能显示不出来,最好用完整 URL。MDX 文件不支持这种方式(组件和 JSX 表达式无法被纯 Markdown 解析)。

收尾:让订阅可被自动发现

生成 rss.xml 后,最好在页面 <head> 里加一行,让读者只输入主页就能被阅读器发现:

<link
  rel="alternate"
  type="application/rss+xml"
  title="你的站点标题"
  href={new URL("rss.xml", Astro.site)}
/>

另外,RSS 默认生成的链接带尾斜杠。如果你在 astro.config.mjs 里设了 trailingSlash: "never",记得在 rss() 里也设 trailingSlash: false,两边保持一致,否则 feed 里的链接和真实文章地址会对不上。

想给 feed 美化样式,还可以用 stylesheet 选项指向一个 .xsl 文件。这些属于锦上添花,按需要加即可。

多个订阅源:按分类拆 feed

一个站点若有多个栏目(比如「教程」和「随笔」),可以生成多个 RSS 文件。做法就是建多个端点,每个端点只取对应集合:

// src/pages/tutorial-rss.xml.js
import rss from '@astrojs/rss';
import { getCollection } from 'astro:content';

export async function GET(context) {
  const posts = await getCollection('tutorial');
  return rss({
    title: '教程订阅',
    description: '只收教程更新',
    site: context.site,
    items: posts.map((post) => ({
      title: post.data.title,
      pubDate: post.data.pubDate,
      description: post.data.description,
      link: `/tutorial/${post.id}/`,
    })),
  });
}

这样读者能只订阅自己关心的栏目。每个端点对应一个独立 URL(如 /tutorial-rss.xml),互不影响。

常见错误排查

写 RSS 时几个高频坑:

  • 链接是相对路径或错了link 必须填能被拼成绝对地址的路径,且 site 要配好。RSS 阅读器一般要求条目链接是完整 URL。
  • site 没填或格式不对:必须是 https:// 开头。context.site 为空时,整个 feed 的链接都会失效。
  • 条目字段缺 titledescription:RSS 标准里两者至少得有一个,否则阅读器可能忽略该条目。用 rssSchema 能强制补齐。
  • 时间格式pubDate 用标准 Date 对象,别传字符串,否则不同阅读器解析不一致。
  • MDX 无法取正文content 用 Markdown 解析的方式不支持 MDX(组件、JSX 表达式无法被纯 Markdown 渲染),MDX 文章建议只输出摘要。

RSS 适合什么类型的站点

不是所有站点都需要 RSS。它最适合「持续产出文章、读者希望被动接收更新」的内容站:博客、周刊、文档更新、播客等。如果你的站点是纯展示型营销页、或交互工具类应用,RSS 价值不大,可以不做。

另外,RSS 和 sitemap 是两套不同东西,别混:sitemap 是给搜索引擎爬虫看的「全站地图」,RSS 是给读者阅读器看的「近期更新流」。两者不冲突,内容站常两个都做——sitemap 管收录,RSS 管订阅。

小结

RSS 输出在 Astro 里就是「装包 + 建一个端点 + 用 rss() 组织 items」。数据来源优先用内容集合,最顺、最稳。配好 site、拼对 link、把 feed 接进 <head>,一个可被订阅的内容站就齐活了。