Butterbase KV 存储与 Realtime 实时订阅指南:如何用 WebSocket 快速构建直播 UI
【免费下载链接】butterbase-ossOpen-source backend-as-a-service. Postgres, auth, storage, functions, AI gateway, MCP.项目地址: https://gitcode.com/gh_mirrors/bu/butterbase-oss
Butterbase 的 KV 存储与 Realtime 实时订阅是两款开箱即用的后端能力:KV 提供按 Key 快速读写的键值存储(会话、计数器、锁、功能开关),Realtime 则通过 WebSocket 把数据库表的每次 INSERT / UPDATE / DELETE 实时广播给前端。两者组合起来,你就能以极低的成本构建"数据一改、界面立变"的直播数据 UI,无需自己维护消息队列或轮询接口。
先搞懂:KV 存什么,Realtime 管什么
很多人分不清这两者的分工,一张表说清楚:
| 你想做的事 | 该用什么 |
|---|---|
| 存会话 Token、购物车、向导进度 | KV(自动过期,免清理) |
| 页面浏览量、限流计数 | KV(incr原子自增) |
| 分布式锁、防重复扣款 | KV(setnx原子占位) |
| 功能开关 / A/B 配置,改值不发布 | KV |
| 数据库行变化后,前端秒级刷新 | Realtime |
| 聊天室、直播评论、多人协作光标 | Realtime(订阅 + Presence) |
官方给出的选型建议很直接:KV 适合"按 Key 访问、会自然过期、不需要关系查询"的数据;消息队列、pub/sub、流式场景交给 Realtime。完整的场景对照见 kv.md 的 "When to use KV" 小节。
KV 快速上手:写入、过期与原子操作
在 Serverless 函数里,KV 通过ctx.kv直接调用,Key 自动按应用隔离,不需要手动加前缀。最常见的三类操作:
// 存一个 1 小时后过期的会话 await ctx.kv.set('session:abc123', { userId: 'u_1' }, { ttl: 3600 }); // 原子计数器(不存在时从 0 开始自增) const views = await ctx.kv.incr('counter:page:/home'); // 分布式锁:Key 不存在才写入成功,TTL 就是锁的租约时长 const acquired = await ctx.kv.setnx('lock:order:99', ctx.requestId, { ttl: 30 });几个新手常踩的点:
- 默认 TTL 是 30 天:不传
ttl时 Key 会在 30 天后自动过期;传{ ttl: null }表示永不过期(见 kv.md 的 TTL 小节)。 - 默认 Key 都是私有的:浏览器/移动端默认读不到 KV,必须显式开放。用一行
expose即可把某个命名空间开放给前端,且支持{user.id}模板让每个用户只访问自己的 Key:
// 每个用户只能读写自己的 profile,别人访问一律 403 await ctx.kv.expose('profile:{user.id}', { read: 'owner', write: 'owner' });会话、锁、限流、幂等键、功能开关五种高频模式都有可复制的完整配方,推荐直接看 kv-recipes.md。不想写代码也可以:在终端执行butterbase kv set feature:new-checkout on,下一行代码都不用改,功能开关即时生效(CLI 命令实现在 kv.ts)。
Realtime 实时订阅:三步开启 WebSocket 推送
Realtime 的原理是:给表装上数据库触发器,行变化通过pg_notify广播到 WebSocket 连接(数据面迁移见 007_realtime.sql,配置表见 022_realtime_config.sql)。
第 1 步:CLI 一键开启
butterbase realtime enable messages命令会列出每张表的配置状态,之后butterbase realtime config随时可查(实现见 realtime.ts)。
第 2 步:前端建立 WebSocket 连接
浏览器端把用户 JWT 放在查询参数即可,RLS 会限制用户只收到自己有权查看的行:
const ws = new WebSocket(`wss://api.butterbase.ai/v1/app_abc123/realtime?token=${token}`); ws.onopen = () => { ws.send(JSON.stringify({ type: 'subscribe', table: 'messages' })); };第 3 步:按字段过滤,只收你要的变化
订阅时可以加filter,只有列值完全相等的变化才会推送——比如直播场景里只关注当前频道的评论:
{ "type": "subscribe", "table": "messages", "filter": { "channel_id": "abc" } }服务端会持续推送change事件(含op、record、old_record、timestamp),另有heartbeat保活。协议全貌见 realtime.md。
构建直播 UI:让数据变化秒级驱动界面
如果不想裸写 WebSocket 协议,TypeScript SDK 的RealtimeClient已经把"连接—订阅—断线重连—心跳检测"全部封装好(见 realtime-client.ts):
// 订阅带过滤条件的变化,断线后自动重连并重放订阅 bb.realtime.on('messages', { channel_id: 'abc' }, (change) => { if (change.op === 'INSERT') addMessageToUI(change.record); });客户端内置指数退避重连(最长 30 秒间隔)和 45 秒心跳超时检测,重连后会自动重新订阅所有表并恢复 Presence 跟踪,省去大量样板代码。
进阶:直播弹幕与多人协作的 Presence
Realtime 除了"数据变化广播",还内置两条对直播 UI 特别实用的通道:
- Presence 在线状态:发送
presence_track并附带元数据(昵称、光标坐标等),服务端会把presence_join/presence_update/presence_leave/presence_state广播给所有跟踪者——协作白板光标、直播间"谁在看"都靠它(协议示例见 realtime.md)。注意 Presence 是内存态,服务重启会重置。 - WebSocket 自定义事件:给函数绑定
websocket触发器后,前端发一条{ "type": "event", "event": "chat_message", "payload": {...} },函数处理完把event_response原路返回——相当于一条低延迟的"请求—响应"旁路,适合弹幕审核、点赞计数这类逻辑。
两个新手要留意的限制:事件是"行级全量"推送(暂不支持列过滤);重连瞬间可能丢事件,客户端应在重连后重新拉取一次状态兜底(见 realtime.md)。
相关文件速查
| 内容 | 路径 |
|---|---|
| KV 概念与 API 详解 | services/docs/src/content/docs/core-concepts/kv.md |
| Realtime 协议与示例 | services/docs/src/content/docs/core-concepts/realtime.md |
| KV 可复制配方集 | services/docs/src/content/docs/guides/kv-recipes.md |
| CLI:realtime enable/config/disable | packages/cli/src/commands/realtime.ts |
| SDK:RealtimeClient 实现 | packages/sdk/src/realtime/realtime-client.ts |
| 数据面 Realtime 迁移 | db/data-plane/007_realtime.sql |
一句话总结:短期状态找 KV,实时推流找 Realtime——先开表、再连 WebSocket、加上 filter 与 Presence,一个会"动"的直播 UI 就完成了。
【免费下载链接】butterbase-ossOpen-source backend-as-a-service. Postgres, auth, storage, functions, AI gateway, MCP.项目地址: https://gitcode.com/gh_mirrors/bu/butterbase-oss
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考