RSS作为站点内容聚合的标准格式,长期被用户用来订阅博客、新闻等站点的更新内容。但传统RSS的工作模式是订阅端定期向源站发起请求检查是否有新内容,这种方式不仅会导致新内容推送延迟,还会给源站带来不必要的请求压力。PubSubHubbub协议的出现改变了这一现状,它基于发布订阅架构,让内容更新可以主动推送到订阅端,实现近乎实时的内容同步。

PubSubHubbub协议核心概念
PubSubHubbub是一个开放的去中心化发布订阅协议,核心角色包含三个部分:
- 发布者(Publisher):拥有RSS或Atom内容源的站点,当内容更新时主动向Hub发送通知
- 订阅者(Subscriber):需要获取内容更新的客户端,向Hub发起订阅请求,接收推送的内容
- Hub:协议的核心中间节点,负责接收发布者的更新通知,再将更新内容推送给所有订阅了该内容的订阅者
协议的工作流程可以简单概括为:订阅者向Hub订阅指定RSS源,发布者更新内容后通知Hub,Hub再将更新内容推送给所有订阅者,整个过程不需要订阅者主动轮询。
PubSubHubbub协议工作流程详解
1. 订阅阶段
订阅者需要向Hub发送订阅请求,请求中包含要订阅的RSS源地址、订阅者的回调接口地址等信息。Hub会验证回调接口的有效性,验证通过后保存订阅关系。
2. 发布阶段
当发布者的RSS内容更新时,发布者会向Hub发送一个更新通知,告知Hub对应的RSS源有新的内容产生。通知中只需要包含RSS源的地址即可,不需要携带完整的内容。
3. 推送阶段
Hub收到发布者的更新通知后,会从发布者处拉取最新的RSS内容,然后将完整的内容推送到所有订阅了该RSS源的订阅者的回调接口中,订阅者收到内容后即可完成更新。
如何实现RSS内容的实时推送和更新
搭建简易Hub服务
我们可以使用Python的Flask框架搭建一个简易的Hub服务,实现订阅管理和推送功能,示例代码如下:
from flask import Flask, request, jsonify
import requests
import hashlib
import hmac
import time
app = Flask(__name__)
# 存储订阅关系的字典,key为topic_url(RSS源地址),value为订阅者回调地址列表
subscriptions = {}
# 验证订阅请求的回调地址有效性
def verify_callback(topic_url, callback_url, lease_seconds):
# 构造验证请求参数
params = {
"hub.mode": "subscribe",
"hub.topic": topic_url,
"hub.challenge": "random_challenge_string",
"hub.lease_seconds": lease_seconds
}
try:
# 向订阅者回调地址发送验证请求
resp = requests.get(callback_url, params=params, timeout=5)
# 如果订阅者返回的响应内容和challenge一致,说明验证通过
if resp.text == "random_challenge_string":
return True
return False
except Exception as e:
print(f"验证回调地址失败:{e}")
return False
# 处理订阅请求
@app.route("/hub", methods=["POST"])
def handle_subscribe():
data = request.form
mode = data.get("hub.mode")
topic_url = data.get("hub.topic")
callback_url = data.get("hub.callback")
lease_seconds = data.get("hub.lease_seconds", 86400)
if mode == "subscribe":
# 验证回调地址有效性
if verify_callback(topic_url, callback_url, lease_seconds):
if topic_url not in subscriptions:
subscriptions[topic_url] = []
if callback_url not in subscriptions[topic_url]:
subscriptions[topic_url].append(callback_url)
return "订阅成功", 200
return "回调地址验证失败", 400
elif mode == "unsubscribe":
if topic_url in subscriptions and callback_url in subscriptions[topic_url]:
subscriptions[topic_url].remove(callback_url)
return "取消订阅成功", 200
return "不支持的模式", 400
# 处理发布者的更新通知
@app.route("/hub/publish", methods=["POST"])
def handle_publish():
topic_url = request.form.get("hub.url")
if not topic_url or topic_url not in subscriptions:
return "无效的RSS源地址", 400
# 从发布者拉取最新的RSS内容
try:
resp = requests.get(topic_url, timeout=10)
latest_content = resp.text
except Exception as e:
print(f"拉取RSS内容失败:{e}")
return "拉取内容失败", 500
# 向所有订阅者推送最新内容
for callback_url in subscriptions[topic_url]:
try:
# 推送内容到订阅者回调接口
requests.post(callback_url, data=latest_content, timeout=5)
except Exception as e:
print(f"推送内容到{callback_url}失败:{e}")
return "推送完成", 200
if __name__ == "__main__":
app.run(host="0.0.0.0", port=5000, debug=True)
发布者接入Hub实现内容更新通知
发布者需要在RSS源中添加Hub的地址声明,并且在内容更新时向Hub发送通知,RSS源中添加Hub声明的示例如下:
<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<atom:link rel="hub" href="http://127.0.0.1:5000/hub"/>
<atom:link rel="self" href="http://ipipp.com/rss.xml"/>
<title>示例站点RSS</title>
<link>http://ipipp.com</link>
<description>示例站点的RSS内容源</description>
<item>
<title>第一篇文章</title>
<link>http://ipipp.com/post/1</link>
<description>这是第一篇文章的内容</description>
</item>
</channel>
</rss>
发布者内容更新后,向Hub发送通知的Python示例代码如下:
import requests
# Hub的发布通知接口地址
hub_publish_url = "http://127.0.0.1:5000/hub/publish"
# 当前更新的RSS源地址
rss_topic_url = "http://ipipp.com/rss.xml"
# 发送更新通知给Hub
response = requests.post(hub_publish_url, data={"hub.url": rss_topic_url})
print(response.text)
订阅者接入Hub接收推送内容
订阅者需要提供一个回调接口来接收Hub推送的内容,同时向Hub发起订阅请求,回调接口的示例代码如下:
from flask import Flask, request
app = Flask(__name__)
# 订阅者的回调接口,用于接收Hub推送的RSS内容
@app.route("/subscriber/callback", methods=["POST"])
def receive_content():
# 获取推送过来的RSS内容
rss_content = request.get_data(as_text=True)
# 这里可以解析RSS内容,处理更新逻辑
print("收到新的RSS内容:")
print(rss_content)
return "接收成功", 200
# 向Hub发起订阅请求的示例
def subscribe_to_hub():
hub_url = "http://127.0.0.1:5000/hub"
topic_url = "http://ipipp.com/rss.xml"
callback_url = "http://127.0.0.1:5001/subscriber/callback"
data = {
"hub.mode": "subscribe",
"hub.topic": topic_url,
"hub.callback": callback_url,
"hub.lease_seconds": 86400
}
response = requests.post(hub_url, data=data)
print(response.text)
if __name__ == "__main__":
# 启动订阅者服务前先发起订阅
subscribe_to_hub()
app.run(host="0.0.0.0", port=5001, debug=True)
注意事项
- 实际生产环境中的Hub需要支持分布式部署,避免单点故障,同时需要处理订阅过期、签名验证等安全机制
- 发布者的RSS源中必须正确添加Hub的声明,否则订阅者无法发现对应的Hub地址
- 订阅者的回调接口需要保证稳定性,避免推送失败导致内容丢失
- 如果需要更高的安全性,可以在推送内容时添加签名验证,防止恶意推送
RSSPubSubHubbub实时推送内容更新修改时间:2026-06-20 21:24:22