理解RSS的工作原理
RSS 是一种基于 XML 的格式,用于提供内容更新的订阅服务。RSS 订阅者通过读取你提供的 RSS 链接获取最新的内容更新。RSS 文件本质上是一个特定格式的 XML 文件,包含了文章的标题、链接、摘要、发布时间等信息。
作为一个前后端分离项目,我所有的博客都存放在后端数据库中,所以我需要在后端项目实现一个RSS订阅接口,来返回我更新的文章。
生成rss文件后,就可以和访问图片一样,直接访问指定地址的xml文件进行RSS订阅。
实现步骤
安装RSS库
npm install rss
实现RSS接口
import { Controller, Get, Res } from '@nestjs/common';
import { Response } from 'express';
import * as RSS from 'rss';
import { BlogService } from './blog.service';
// RSS 订阅接口
@Get('rss')
async getRssFeed(@Res() res: Response) {
……
}
初始化RSS订阅
const feed = new RSS({
// RSS名称
title: 'FlowersInk RSS Feed',
// RSS介绍
description: '订阅花墨的最新文章',
// RSS订阅地址
feed_url: 'https://flowersink.com/rss.xml',
// 主站地址
site_url: 'https://flowersink.com/',
// 语言
language: 'zh-CN',
// 日期,设置为即刻
pubDate: new Date(),
});
筛选博客
因为我的博客分为文章和问题两种类型,所以需要进行筛选。
又因为我使用的是我提前写好的博客搜索接口,所以需要必填其他筛选条件(填空即可)
// 筛选出 type 为 '文章' 的博客(获取全部符合条件的博客)
const { blogs } = await this.blogService.findAllBlog(1, 1000, {
type: '文章',
title: undefined,
content: undefined,
tag: undefined,
date: null,
star: undefined,
});
将每篇博客添加到RSS订阅
blogs.forEach((blog) => {
feed.item({
title: blog.title, // 博客标题
description: blog.content.slice(0, 200), // 截取内容的前200字符
url: `https://flowersink.com/blog/blog-detail/${blog.id}`, // 文章详情链接
author: '再花', // 添加作者
categories: blog.tag ? blog.tag.split(',') : [], // 使用 tag 作为标签
date: blog.date, // 发布日期
});
});
返回RSS订阅xml
// 设置响应头并返回 RSS 内容
res.type('application/rss+xml');
res.send(feed.xml({ indent: true }));
完整代码
import { Controller, Get, Res } from '@nestjs/common';
import { Response } from 'express';
import * as RSS from 'rss';
import { BlogService } from './blog.service';
@Controller('blog')
export class BlogController {
constructor(private readonly blogService: BlogService) {}
@Get('rss')
async getRssFeed(@Res() res: Response) {
const feed = new RSS({
title: 'FlowersInk RSS Feed',
description: '订阅花墨的最新文章',
feed_url: 'https://flowersink.com/rss.xml',
site_url: 'https://flowersink.com/',
language: 'zh-CN',
pubDate: new Date(),
});
const { blogs } = await this.blogService.findAllBlog(1, 1000, {
type: '文章',
title: undefined,
content: undefined,
tag: undefined,
date: null,
star: undefined,
});
blogs.forEach((blog) => {
feed.item({
title: blog.title,
description: blog.content.slice(0, 200),
url: `https://flowersink.com/blog/blog-detail/${blog.id}`,
author: '再花',
categories: blog.tag ? blog.tag.split(',') : [],
date: blog.date,
});
});
res.type('application/rss+xml');
res.send(feed.xml({ indent: true }));
}
}
为RSS订阅增加缓存
因为RSS并不需要频繁更新(我有可能一周才写一篇文章),那就可以为RSS增加一个缓存机制节省服务器资源。
使用NestJS内置的CacheModule实现就会非常简单。
安装相关依赖
npm install cache-manager @nestjs/cache-manager
配置缓存模块
import { Module, CacheModule } from '@nestjs/common';
import { CacheModuleOptions } from '@nestjs/cache-manager';
@Module({
imports: [
……
CacheModule.register<CacheModuleOptions>({
ttl: 300, // 缓存时间(秒)
max: 100, // 缓存最大条目数
}),
],
})
export class AppModule {}
给方法配置缓存
import { Cache } from 'cache-manager';
export class BlogController {
constructor(
private readonly blogService: BlogService,
@Inject(CACHE_MANAGER) private cacheManager: Cache,
){}
@Get('rss')
async getRssFeed(@Res() res: Response) {
// 检查缓存
let cachedFeed = await this.cacheManager.get<string>('rss_feed');
if (!cachedFeed) {
// 初始化RSS等后续操作
}
}
}
设置清理缓存逻辑
当发布新博客的时候,对缓存进行清理
// 创建新博客
async createBlog(createBlogDto: CreateBlogDto): Promise<Blog> {
const newBlog = this.blogRepository.create(createBlogDto); // 创建博客实例
await this.cacheManager.del('rss_feed'); // 清理缓存
return this.blogRepository.save(newBlog); // 保存实例到数据库
}
验证
我们可以在网站:validator.w3.org/feed/ 来验证RSS订阅是否生效,如图所示