在当今数字化时代,去中心化社交网络正成为对抗中心化平台的有效替代方案。正如 Ben Werdmuller 在其 FediForum 主题演讲中强调,“开放社交网络终于起飞”,它提供了一个安全的空间,让社区在不依赖单一公司的情况下组织和交流。ActivityPub 作为 W3C 标准协议,正是实现这种联邦化社交的核心技术。它允许不同服务器间的用户无缝互动,支持 Mastodon 等流行平台。本文聚焦于在 Node.js 环境中实现 ActivityPub 服务器,特别强调 WebFinger 发现机制和 ActivityStreams 2 (AS2) 序列化,用于联邦发布和关注者同步。通过这一实现,开发者可以构建兼容 Mastodon 网络的节点,确保内容跨实例传播,同时维护数据隐私和互操作性。
ActivityPub 的核心在于其双 API 设计:客户端到服务器 (C2S) API 用于用户操作,服务器到服务器 (S2S) API 用于联邦通信。WebFinger 协议是发现用户 Actor 的关键入口,当用户尝试关注如 user@domain.com 时,客户端会查询 domain 的 .well-known/webfinger 端点,返回 Actor 的 JSON-LD 描述,包括 outbox 和 inbox URL。这确保了跨域发现的标准化。AS2 则定义了活动数据的 JSON-LD 格式,例如 Create 活动用于发布帖子:{"@context": "https://www.w3.org/ns/activitystreams", "type": "Create", "actor": "https://domain.com/users/user", "object": {"type": "Note", "content": "Hello Fediverse!"}}。这些机制使服务器能处理 Mastodon 兼容的活动,确保序列化后的数据可被其他实例解析和验证。
在 Node.js 中实现这一服务器,最简单的方式是基于 Express 框架,结合 SQLite 存储用户数据和活动日志。安装依赖后,配置服务器监听端口(如 3000),并设置 HTTPS 以支持 HTTP Signatures 验证。核心端点包括 /users/{username} 返回 Actor JSON,/.well-known/webfinger 处理发现查询。使用 crypto 模块生成 RSA 密钥对,用于签名活动。示例代码如下:
const express = require('express');
const sqlite3 = require('sqlite3').verbose();
const app = express();
const db = new sqlite3.Database('activitypub.db');
// 初始化数据库表
db.run(CREATE TABLE IF NOT EXISTS actors ( name TEXT PRIMARY KEY, privkey TEXT, pubkey TEXT, actor JSON, followers JSON ));
// WebFinger 端点
app.get('/.well-known/webfinger', (req, res) => {
const resource = req.query.resource;
if (resource.startsWith('acct:')) {
const [, username, domain] = resource.match(/acct:([^@]+)@(.+)/);
if (domain !== process.env.DOMAIN) return res.status(404).send();
db.get('SELECT actor FROM actors WHERE name = ?', [username], (err, row) => {
if (err || !row) return res.status(404).send();
res.json({
subject: resource,
links: [{ rel: 'self', type: 'application/activity+json', href: JSON.parse(row.actor).id }]
});
});
}
});
// Actor 端点
app.get('/users/:username', (req, res) => {
const { username } = req.params;
db.get('SELECT actor FROM actors WHERE name = ?', [${username}@${process.env.DOMAIN}], (err, row) => {
if (err || !row) return res.status(404).send();
res.json(JSON.parse(row.actor));
});
});
// Outbox 端点(简化)
app.post('/users/:username/outbox', authenticateSignature, (req, res) => {
// 处理 Create 活动,广播到 followers
const activity = req.body;
if (activity.type === 'Create') {
broadcastToFollowers(username, activity);
}
res.status(201).json(activity);
});
app.listen(3000, () => console.log('Server running on port 3000'));
这一实现确保了 AS2 序列化的正确性,所有活动均以 JSON-LD 格式交换。联邦发布时,服务器需验证传入活动的签名(使用 http-signature 库),然后将 Create 活动 POST 到每个 follower 的 inbox URL。关注者同步依赖 Follow 活动处理:接收 Follow 时,回复 Accept 活动,并更新本地 followers 列表(JSON 数组存储 URL)。
为确保可靠的联邦操作,设置关键参数:签名密钥长度至少 2048 位,超时阈值 30 秒(使用 axios 配置),重试机制 3 次(指数退避)。监控点包括:活动验证失败率(<1%),inbox 交付延迟(<5s),followers 列表一致性(定期校验)。回滚策略:若同步失败,缓存活动至队列(如 Redis),离线重发。风险包括签名伪造,缓解方式是严格验证 Digest 和 Signature 头;规模扩展时,迁移至 PostgreSQL,支持并发查询。
在 Mastodon 兼容网络中,这一服务器可无缝集成:用户从 Mastodon 关注本地 Actor,后续帖子自动出现在其时间线。实际部署时,使用 PM2 进程管理器运行 Node.js,确保高可用。测试工具如 fedify CLI 可模拟联邦交互。总之,这一实现不仅体现了 ActivityPub 的强大,还为去中心化社交提供了可落地路径,推动开放 web 的发展。(1024 字)