作为一个博客爱好者,我是很喜欢RSS/Atom Feed的方式,可以很方便的订阅别人的博客、新闻等内容,经常浏览别人的博客,发现RSS Feed Reader都会显示一个添加订阅的图标,挺方便的。
但是作为一个前端开发,自己的博客居然没有RSS/Atom订阅,不能忍,果断花2小时加上再说。
1. 什么是RSS/Atom
引用维基百科的解释:
RSS(英文全称:RDF Site Summary 或 Really Simple Syndication),中文译作简易资讯聚合,也称聚合内容,是一种消息来源格式规范,用以聚合多个网站更新的內容并自动通知网站订阅者。使用RSS后,网站订阅者便无需再手动查看网站是否有新的內容,同时 RSS 可將多个网站更新的內容进行整合,以摘要的形式呈现,有助于订阅者快速获取重要信息,并选择性地点阅查看。
Atom是一对彼此相关的标准。Atom供稿格式(Atom Syndication Format)是用于网站消息来源,基于XML的文档格式;而Atom出版协定(Atom Publishing Protocol,简称AtomPub或APP)是用于新增及修改网络资源,基于HTTP的协议。
它借鉴了各种版本RSS的使用经验,被许多的聚合工具广泛使用在发布和使用上。Atom供稿格式设计作为RSS的替代品;而Atom出版协定用来取代现有的多种发布方式(如Blogger API和LiveJournal XML-RPC Client/Server Protocol)。Google提供的多种服务正在使用Atom。Google Data API(GData)亦基于Atom。
简单来说,就是RSS/Atom提供了一种统一的数据格式规范,网站可以将内容通过这种规范进行编码生成,订阅者通过RSS/Atom阅读器解析这些数据,就能实现在不打开网站的情况下实现网站内容的阅读。
2. Django的Feed聚合框架
Django 提供了一个高级的 feed 聚合生成框架来创建 RSS 和 Atom Feed。
同时还提供了一个低级别的 feed 生成 API。如果你想在网络内容之外或以其他较低级别的方式生成 feed,可以使用这个 API。
一个简单的例子
from django.contrib.syndication.views import Feed
from django.urls import reverse
from policebeat.models import NewsItem
class LatestEntriesFeed(Feed):
title = "Police beat site news"
link = "/sitenews/"
description = "Updates on changes and additions to police beat central."
def items(self):
return NewsItem.objects.order_by('-pub_date')[:5]
def item_title(self, item):
return item.title
def item_description(self, item):
return item.description
# item_link is only needed if NewsItem has no get_absolute_url method.
def item_link(self, item):
return reverse('news-item', args=[item.pk])
要连接到这个 feed 的 URL,在你的 URLconf 中放入一个 Feed 对象的实例。例如:
from django.urls import path
from myproject.feeds import LatestEntriesFeed
urlpatterns = [
# ...
path('latest/feed/', LatestEntriesFeed()),
# ...
]
指定 feed 的类型
默认情况下,这个框架中产生的 feed 使用 RSS 2.0。
要改变这一点,可以在你的 Feed
类中添加一个 feed_type
属性,像这样:
from django.utils.feedgenerator import Atom1Feed
class MyFeed(Feed):
feed_type = Atom1Feed
自定义 feed 对象
一般情况下,默认提供的 api 已经能够完成消息聚合了,但是如果我们需要在生成内容中增加新的字段,又或者提供 django feed 框架没有的聚合消息,那就需要自定义 feed 对象了。
一个简单例子:
class iTunesFeed(Rss201rev2Feed):
def root_attributes(self):
attrs = super().root_attributes()
attrs['xmlns:itunes'] = 'http://www.itunes.com/dtds/podcast-1.0.dtd'
return attrs
def add_root_elements(self, handler):
super().add_root_elements(handler)
handler.addQuickElement('itunes:explicit', 'clean')
我这次要提供的是Atom Feed,默认已经提供这种类型,但是唯一的问题是默认并没有 content 字段,所以需要自定义一下:
from django.contrib.syndication.views import Feed
from django.urls import reverse
from django.utils.feedgenerator import Atom1Feed
from policebeat.models import NewsItem
class Atom1FeedExtend(Atom1Feed):
def add_item_elements(self, handler, item):
super().add_item_elements(self, handler, item)
handler.addQuickElement('content', item.get('content', ''), { "type": "html" })
class LatestEntriesFeed(Feed):
feed_type = Atom1FeedExtend
title = "Police beat site news"
link = "/sitenews/"
description = "Updates on changes and additions to police beat central."
def items(self):
return NewsItem.objects.order_by('-pub_date')[:5]
def item_title(self, item):
return item.title
def item_description(self, item):
return item.description
# item_link is only needed if NewsItem has no get_absolute_url method.
def item_link(self, item):
return reverse('news-item', args=[item.pk])
def item_extra_kwargs(self, item):
return {
"content": item.content
}
到这里,服务端已经是准备好了。
3. 页面提供RSS/Atom Feed订阅入口
有人可能会想,这里有什么要做的,就是提供个链接给阅读器就行了啊。
是的,说的没错,但是只能说说对了一半。提供订阅链接很简单,一个 a 标签,href 填 feed 地址就行,用户复制或者点击就能触发订阅器的订阅提示。
但是就像我开头说的,基本上网站如果提供了 feed 消息聚合了,那么订阅器就会自动的提示用户,这是怎么做到的呢,这就要说一下目前 RSS/Atom 阅读器的主动探测方式了。
这里就以 RSSHub Radar 为例,介绍下阅读器是怎么主动检测页面的 RSS/Atom 链接的。
首先遍历页面所有的链接肯定是不可取的,还在标准中指定了一种特殊 MIME 类型的 link 标签来指明 RSS/Atom 链接,link[type="application/rss+xml"] 和 link[type="application/atom+xml"],RSSHub Radar 正是通过这个标签来检测页面是否有自带 RSS,具体实现在这里。
只要提供了这个 link 标签,那基本上阅读器都会能主动提示订阅了。
4. 参考
5. 最后
本博客的 Atom 订阅已经上线,欢迎订阅。