使用 NodeJS 快速搭建代理 RSS 订阅服务

RSS 阅读器是我的内容消费神器,因为它免受平台限制,把散落于各大内容平台之外的珍贵资源汇集到一处,这类内容往往来自个人或公司的高质量创作,而非单纯的营销信息。

但是,我发现一些内容原生并不支持 RSS 订阅功能。这就促使我手动构建一个订阅服务,以便能够在我的 RSS 阅读器中订阅这些内容。

本文将介绍如何利用 serverless 模式搭建 www.arcblock.io/blog/ 的代理 RSS 订阅服务。

代码已开源:github.com/linchen1987...

RSS 系统结构

首先,了解一下 RSS 系统的三大组成部分:RSS 阅读器、RSS 源、和 RSS 发布器。

  • RSS 阅读器是我们直接用来阅读内容的客户端,如 Feedly feedly.com/
  • RSS 源则是一个可以公开访问的 XML 文件,例如阮一峰的博客 RSS 源 www.ruanyifeng.com/blog/atom.x...
  • RSS 发布器的职责是更新新内容到 RSS 源中,如阮一峰发布新文章时,他的 RSS 发布器便会将文章更新到其博客的 RSS 源中。

Serverless 的本质

Serverless 概念的核心是无需自己管理服务器。例如,你在自己的服务器上搭建并维护一个博客,这就需要服务器。相反,如果您将文章发布到掘金,可以把掘金视为为您的文章提供了 serverless 服务。

实现步骤

以订阅 www.arcblock.io/blog/ 的内容为例,下面是实现步骤:

  1. 获取信息源 :想要订阅的内容列表页即是信息源。因为列表页总会按文章发布时间排序,把最新发布的文章展示在最前面。我想订阅的信息源是 www.arcblock.io/blog/
  2. 解析信息源 :找到内容列表页后,先查看是否有 API 可用(通过浏览器的开发者工具查看网络请求)。如果有 API,可以直接从 API 接口获取内容。如果没有,就需要抓取网页内容,并解析出文章。例如,我找到了 Arcblock Blog 的 API:www.arcblock.io/blog/api/bl...
js 复制代码
const thirdPartyApiUrl = 'https://www.arcblock.io/blog/api/blogs?page=1&size=20';
const response = await axios.get(thirdPartyApiUrl);
const data = response.data.data || [];
const blogs = [];

// 为每个博客条目添加到feed
data.forEach((item) => {
  blogs.push({
    title: blog.title,
    description: blog.excerpt,
    guid: blog.id,
    url: `https://www.arcblock.io/blog/${blog.slug}`,
    date: blog.publishTime,
  });
});
  1. 将信息解析成 XML 格式:处理获取到的信息,将其转换成适合 RSS 阅读器读取的 XML 格式。
js 复制代码
import RSS from 'rss';

var feed = new RSS({
  title: 'ArcBlock Blog',
  description: 'Latest blogs from arcblock.io',
  feed_url:
  'https://link-general-public.s3.ap-northeast-3.amazonaws.com/arcblock-blog-feed.xml',
  site_url: 'https://www.arcblock.io/blog',
});

blogs.forEach((blog) => {
  feed.item(blog);
});
  1. 发布 XML 至公网:无需搭建自己的服务器,只需将 XML 文件发布到任何支持静态内容托管的服务,如 GitHub、AWS S3、Cloudflare R2、阿里云 OSS 等。在本例中,我将 XML 发布到了 AWS S3。
js 复制代码
import fs from 'node:fs';
import path from 'node:path';
import 'dotenv-flow/config';
import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3';

export default async function upload(file) {
  const s3Client = new S3Client({});

  const bucketName = process.env.AWS_BUCKET;
  const fileStream = fs.createReadStream(file);

  await s3Client.send(
    new PutObjectCommand({
      Bucket: bucketName,
      Key: path.basename(file),
      Body: fileStream,
      ACL: 'public-read',
      ContentType: 'application/xml',
    })
  );
}
  1. 定时更新:同样,无需自建服务来实现定时更新功能。在本例中,我使用了 GitHub Actions 来定期执行更新操作,每天更新一次。
yml 复制代码
name: Schedule

on:
  schedule:
    - cron: '0 0 * * *'

jobs:
  main:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v2
        with:
          fetch-depth: 0

      - uses: pnpm/action-setup@v2.0.1
        with:
          version: latest

      - name: Use Node.js
        uses: actions/setup-node@v2
        with:
          node-version: '18'
          cache: 'pnpm'

      - name: Setup
        run: npm add -g @antfu/ni

      - name: Install
        run: nci

      - name: Run
        env:
          AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
          AWS_BUCKET: ${{ secrets.AWS_BUCKET }}
          AWS_REGION: ${{ secrets.AWS_REGION }}
          AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
        run: 'node tools/fetch-arcblock-blog.js'

总结

通过上述步骤,你就能搭建起一个能够代理不支持 RSS 的内容源的订阅服务,享受在 RSS 阅读器中阅读这些内容的便捷。

我们不仅要学会如何写代码,还要学会如何使用工具,站在巨人的肩膀上快速搭建我们想要的功能。

相关推荐
程序员的世界你不懂10 分钟前
【Flask】测试平台开发,新增说明书编写和展示功能 第二十三篇
java·前端·数据库
索迪迈科技12 分钟前
网络请求库——Axios库深度解析
前端·网络·vue.js·北京百思可瑞教育·百思可瑞教育
gnip20 分钟前
JavaScript二叉树相关概念
前端
attitude.x1 小时前
PyTorch 动态图的灵活性与实用技巧
前端·人工智能·深度学习
β添砖java1 小时前
CSS3核心技术
前端·css·css3
ChinaRainbowSea1 小时前
7. LangChain4j + 记忆缓存详细说明
java·数据库·redis·后端·缓存·langchain·ai编程
舒一笑1 小时前
同步框架与底层消费机制解决方案梳理
后端·程序员
minh_coo1 小时前
Spring框架事件驱动架构核心注解之@EventListener
java·后端·spring·架构·intellij-idea
空山新雨(大队长)2 小时前
HTML第八课:HTML4和HTML5的区别
前端·html·html5