原始资料:PartyKit 官方文档 · PartyKit 官网
AI 参与说明(Agent:Codex):本文由 Codex 根据上述资料及 Cloudflare、PartyServer 的一手文档调研、撰写并校验。资料核对日期为 2026-09-28;PartyKit 文档部分页面标注的最近更新日期为 2025-03-26,涉及平台能力时请继续核对其最新说明。本次运行的完整模型标识与 reasoning effort 未取得运行记录。
结论: 已有 Cloudflare Workers / Durable Objects 工程,优先评估 PartyServer;希望把实时能力作为独立服务接入时,评估 PartyKit。
| 英文术语 | 中文名称 | 简要解释 |
|---|---|---|
| PartyKit | PartyKit | 提供实时协作服务、CLI 和部署平台的项目;其 room 由 Durable Object 承载。 |
| Party / room | 实时房间 | 用业务 ID 寻址的单个协作实例,例如一份文档或一场投票。 |
| Durable Object | 持久化对象 | Cloudflare 中按对象 ID 定位、集中协调请求并持有私有存储的运行实例。 |
| PartyServer | PartyServer | Cloudflare 维护的 Durable Objects 库,为房间路由、WebSocket 生命周期和广播提供封装。 |
| cloud-prem | 自有账户部署 | 使用 PartyKit CLI,把 PartyKit 项目部署到自己的 Cloudflare 账户。 |
PartyKit 把每个 room 放在一个 Cloudflare Durable Object 上。Cloudflare 维护的 partyserver 则是受 PartyKit 启发、直接扩展 Durable Object 的库,便于在自己的 Wrangler 项目中结合 D1、R2 或 Queues。PartyKit 的 cloud-prem 是把 PartyKit 项目部署到自有 Cloudflare 账户的另一条路径,不能理解成把托管平台装进现有 Worker。PartyKit 运行模型 · PartyServer 仓库 · cloud-prem 指南
先分清三条接入路径
一个 PartyKit room 由一个 Durable Object 承载。 PartyKit 根据 room ID 把 HTTP 请求和 WebSocket 连接送到对应实例;同一个 ID 指向同一逻辑房间,不同 ID 形成不同房间。Party.Server、Party.Room、room.storage 属于 PartyKit 平台 API。How PartyKit works · Party.Server API
| 路径 | 运行与部署 | 怎样接入现有 Worker | 适合的起点 |
|---|---|---|---|
| PartyKit 托管平台 | partykit CLI 部署;PartyKit 管理资源和路由 | 通过公开的 HTTP / WebSocket 地址通信 | 应用不依赖现有 Cloudflare bindings,想快速增加实时能力 |
| PartyKit cloud-prem | 同一套 PartyKit 项目通过 CLI 部署到自有 Cloudflare 账户 | 仍按独立服务考虑,通过 HTTP / WebSocket 地址通信 | 需要自有账户或域名,同时保留 PartyKit 开发模式 |
| PartyServer | partyserver 作为依赖放进自己的 Wrangler 项目;DO class、binding 和存储声明由自己管理 | Worker 直接路由到本项目的 Durable Object,使用 env 中的其他 bindings | 已有 Workers、D1、R2、Queues 等资源,想把实时房间纳入同一工程 |
这里有一个容易误解的地方:部署到同一个 Cloudflare 账户,不等于自动获得现有 Worker 的 bindings。 2026-09-28 可访问的 PartyKit cloud-prem 指南仍把 KV、R2、D1 等更多 bindings,以及“在 Wrangler 项目里运行 PartyKit”列在未来规划中。这是该指南的能力边界说明,不能据此断言以后一定不会支持;在拿到可验证的配置和运行结果前,不应把 cloud-prem 写成现有 Worker 的一个普通依赖。PartyServer 的 README 则明确要求自行配置 Durable Object,并使用 Wrangler 原生 bindings。PartyKit cloud-prem 指南 · PartyServer README
这两套 API 也不能混用。PartyKit 的回调是 onMessage(message, sender),状态从 this.room.storage 访问;PartyServer 的回调是 onMessage(connection, message),Durable Object 的存储从 this.ctx.storage 访问。迁移时还要检查 URL、认证、存储格式和房间 ID,不能只替换包名。PartyKit Server API · PartyServer README
Cloudflare 技术栈里怎么组合
下图展示的是PartyServer 路径:普通 HTTP 与 WebSocket 可以进入同一个 Worker,再由它将实时连接路由到按房间 ID 划分的 Durable Object。图中的 D1、R2、Queues 是按业务需要增加的 Wrangler bindings,不是这个最小示例的依赖。
flowchart TB
C["浏览器 / 移动客户端"] --> W["Worker:认证、HTTP API、路由"]
W -->|"routePartykitRequest"| P["PartyServer:按 room ID 定位"]
P --> D["RoomServer Durable Object"]
D --> S["私有 SQLite / KV API"]
D -.->|"按需使用 binding"| E["D1 / R2 / Queues"]
W -.->|"按需使用 binding"| E
PartyServer 继承 DurableObject,没有另建数据库或运行时。 它补的是房间路由、连接生命周期和广播 API。房间内需要串行协调的状态可以放在该 Durable Object 的私有存储;跨房间列表、检索或报表通常还需要 D1 等可查询的数据层。后一句是基于各存储边界的工程设计建议,不是 PartyServer 自动提供的数据同步功能。PartyServer README · Durable Objects 存储
| 场景 | 建议放在哪里 | 通过标准 |
|---|---|---|
| 在线成员、协作光标、直播互动、房间内投票 | 一个业务 room 对应一个 PartyServer / Durable Object;Worker 负责入口鉴权 | 两个客户端进入同一 room 后能互相收到消息;不同 room 互不广播 |
| 文档协同编辑 | 先选 PartyKit 的 Y-PartyKit,或 Workers 内的 Y-PartyServer,再单独设计文档快照与恢复 | 断线重连后能从持久数据恢复;不要只保存内存里的 Yjs 状态 |
| 现有 Worker 要触发房间事件 | Worker 经 Durable Object binding 定位 PartyServer;独立 PartyKit 服务则经其 HTTP 接口 | 服务端事件只进入目标 room,并通过身份校验;重复投递可识别 |
| 跨 room 查询、文件与可靠异步任务 | D1 负责可查询事实,R2 保存文件,Queues 处理异步工作;room 只协调自己的实时状态 | 列表查询不需要扫描所有 room;失败任务可重试,外部副作用有幂等策略 |
这些是职责划分与验收建议。PartyKit 文档说明可以用 room.storage 持久化房间数据,也可以调用外部数据库或 API;PartyServer 直接继承 Durable Object,因此可使用自身的 storage 和 Wrangler 授予的 bindings。不要把单个房间当成全站唯一的广播点;一个热点 Durable Object 仍是一个协调边界。PartyKit storage 指南 · PartyServer README · Durable Objects 最佳实践
API Worker 与实时 Worker 分开部署时
如果由自己管理两个 Worker,Cloudflare 提供两种直接调用路径。Service bindings 让 API Worker 调用实时 Worker 的 fetch() 或其公开 RPC 方法;external Durable Object binding 则可在调用方配置 script_name 和 DO class_name,直接定位另一个 Worker 定义的 Durable Object。前者经过目标 Worker 的入口逻辑,后者直接取得指定 DO namespace;需要哪种边界,应按认证与部署职责决定。调用方与目标服务需满足 Cloudflare 对绑定账户、部署顺序和配置的要求。Service bindings · Wrangler Durable Objects bindings
这两种方式适合自行管理脚本和 class 名称的 PartyServer 工程。PartyKit cloud-prem 指南没有给出现有 Worker 可直接绑定其生成资源的稳定配置;在没有核实部署产物与官方支持边界前,按公开 HTTP / WebSocket 接口集成更稳妥。PartyKit cloud-prem 指南
最小可运行示例:一个 Worker 加一个 PartyServer room
以下示例是公开测试房间,用于确认 Worker 路由、Durable Object 和 WebSocket 广播的关系;它没有登录与写入权限控制,不应原样用于私有协作数据。示例按 2026-09-28 核对的 partyserver 仓库版本 0.5.10 编写;新建项目使用本机 Node.js/npm 与 Cloudflare 账户,本地运行只需前两者。PartyServer 的上游 README 仍展示旧式 migrations;这里按照 Cloudflare 当前文档为新 Durable Object class 使用声明式 exports 和 SQLite。PartyServer package.json · PartyServer README · Durable Object class exports
在一个新的、独立的项目目录中安装依赖(以下命令不会部署):
npm init -y
npm install partyserver@0.5.10
npm install --save-dev wrangler@4.131.0
mkdir -p src
src/index.js:
import { routePartykitRequest, Server } from "partyserver";
export class RoomServer extends Server {
static options = { hibernate: true };
onMessage(connection, message) {
if (typeof message !== "string" || message.length > 1024) {
connection.close(1009, "Message too large");
return;
}
this.broadcast(JSON.stringify({
room: this.name,
from: connection.id,
text: message,
}));
}
}
export default {
async fetch(request, env) {
if (new URL(request.url).pathname === "/health") {
return Response.json({ ok: true });
}
return (await routePartykitRequest(request, env)) ??
new Response("Not Found", { status: 404 });
},
};
wrangler.jsonc:
{
"name": "partyserver-room-demo",
"main": "src/index.js",
"compatibility_date": "2026-09-17",
"durable_objects": {
"bindings": [
{ "name": "RoomServer", "class_name": "RoomServer" }
]
},
"exports": {
"RoomServer": { "type": "durable-object", "storage": "sqlite" }
}
}
compatibility_date 使用 2026-09-17,因为本例固定的 Wrangler 4.131.0 内置本地 runtime 支持到该日期;把它直接写成文章日期 2026-09-28 会使 wrangler dev 启动失败。升级 Wrangler 后可再按其支持范围调整。
运行 npx wrangler dev,然后请求 http://127.0.0.1:8787/health,预期得到 {"ok":true}。在浏览器控制台运行以下 JavaScript;等待两个连接都打开后发送,两个连接应各收到包含 room: "demo" 与 text: "hello" 的消息。
const url = "ws://127.0.0.1:8787/parties/room-server/demo";
const sockets = [new WebSocket(url), new WebSocket(url)];
await Promise.all(sockets.map((socket) => new Promise((resolve) => {
socket.addEventListener("open", resolve, { once: true });
})));
sockets.forEach((socket, index) => {
socket.addEventListener("message", (event) => console.log(index, event.data));
});
sockets[0].send("hello");
routePartykitRequest() 将 /parties/room-server/demo 中的 room-server 匹配到 RoomServer binding,把 demo 当作房间名;RoomServer 的 this.name 就是该房间名。若把第二个 URL 的 demo 换成 other,它应收不到前一个 room 的广播。PartyServer 路由说明
本地实测(2026-09-28):使用上述固定依赖启动 Wrangler,GET /health 返回 {"ok":true};两个连接进入 demo 后各收到一条 hello 广播,进入 other 的第三个连接没有收到这条消息。WebSocket 检查使用本地 Node 客户端完成,未进行远端部署。
这个示例中的 hibernate: true 让空闲 WebSocket 连接能够由平台保持,而 RoomServer 实例可能重新创建;不要依赖 class 字段保存需要恢复的业务状态。真正需要持久化的房间状态写入 this.ctx.storage,并在唤醒时按需读取。原 PartyKit 平台也有 Hibernation,但开关写在实例的 options,不是 PartyServer 的 static options;两边设置不能混贴。PartyServer Hibernation · PartyKit Hibernation
若继续使用 PartyKit 平台
应用原本在 Worker、Pages、其他云或传统服务器上,都可以通过标准 HTTP / WebSocket 与独立的 PartyKit 项目通信。PartyKit 项目可以用 npx partykit@latest init、npx partykit dev 开发;发布到自有 Cloudflare 账户时,官方命令是 npx partykit deploy --domain <你的域名>,并要求在部署环境提供 CLOUDFLARE_ACCOUNT_ID 与 CLOUDFLARE_API_TOKEN。部署会改动远端资源,先在测试账户和域名完成验证,不把示例占位符当真实凭据。现有项目接入 · cloud-prem 指南
PartyKit 的 onBeforeConnect 与 onBeforeRequest 可分别拦截 WebSocket 握手和 HTTP 请求。浏览器若直连 PartyKit 域名,现有 Worker 对自己 API 的鉴权不会自动保护该连接;PartyKit 侧仍要验证会话和 room 权限。连接成功后还应验证每条消息的类型、大小与业务权限。PartyKit Authentication · Validating client inputs
PartyKit 官网在本次核对时把其托管 Individual 方案的 storage 描述为每 24 小时清空。因此需要长期保存的协作文档或审计数据,不应仅依据“有 room.storage API”就把托管免费环境当作持久数据库;先核对实际部署方案及其存储条款。这个官网价格与服务说明可能变化。PartyKit 官网 Pricing
选型时检查的边界
- 是否已有 Worker 与 Cloudflare bindings? 已有且希望共享部署与环境配置,优先从 PartyServer 入手;纯实时增量、应用可接受独立服务时,先试 PartyKit 平台。
- 状态归谁管理? 房间内顺序、连接和短期协同属于 Durable Object;需要跨房间查询的业务事实另设可查询存储,并明确更新与重试策略。
- 入口由谁认证? 对 HTTP 与 WebSocket 分别验证身份、room 访问权、消息大小与频率;示例的公开广播只适合本地验证。
- 是否真需要 PartyServer? 若只有一个计数器或既有 DO RPC,Cloudflare 原生 Durable Objects 就足够;PartyServer 的收益主要来自房间式 URL、WebSocket hooks 和广播封装。PartyServer 功能
相关站内阅读:Workers 运行时 API 与 Bindings · Durable Objects 使用方式与接口 · Queues 生产消费与重试