如何不使用Supabase JS SDK,通过原生WebSocket监听数据库变更?
问题:不借助Supabase JS SDK,用原生WebSocket订阅数据库变更通道可行吗?
根据Supabase Realtime文档,它通过WebSocket向客户端推送新事件,但能否不依赖官方JS SDK,直接用浏览器原生WebSocket对象或第三方WebSocket库(比如socket.io)订阅数据库变更通道?
我尝试用以下原生WebSocket代码连接Supabase托管项目,监听表的INSERT事件:
var ws = new WebSocket("wss://[project-ref].supabase.co/realtime/v1/websocket?apikey=[anon-token]&log_level=info&vsn=1.0.0&schema=public&table=MyTable&event=*&channel=mychannel"); ws.onopen = function () { console.log('socket connection opened properly'); ws.send("Hello World"); // send a message console.log('message sent'); }; ws.onmessage = function (evt) { console.log("Message received = " + evt.data); };
注:我使用了Supabase托管项目中的anon API密钥。
但向表中插入新行时,从未收到Supabase返回的事件。而使用Supabase JS SDK的以下代码却能正常工作:
supabase .channel('mychannel') .on('postgres_changes', { event: '*', schema: 'public', table: 'MyTable' }, payload => { console.log('Change received!', payload) }) .subscribe()
请问如何让原生WebSocket方案生效?或者该方案是否可行?
解答
完全可以用原生WebSocket实现,你的问题出在没有遵循Supabase Realtime的WebSocket协议规范——它不是简单通过URL参数完成订阅,而是需要在连接建立后发送特定格式的JSON消息,完成通道订阅、鉴权等流程。
核心问题分析
你当前的代码仅建立了WebSocket连接,发送的"Hello World"不符合Supabase Realtime基于Phoenix Channels协议的消息格式,服务端无法识别你的订阅请求,自然不会推送事件。
修正后的原生WebSocket实现步骤
- 简化连接URL:只保留必要参数(
apikey、vsn),schema、table、event等订阅参数不需要放在URL里。 - 发送标准化订阅消息:连接打开后,发送
phx_join类型的JSON消息,携带订阅配置与鉴权信息。 - 解析服务端响应:监听并解析服务端返回的JSON消息,筛选出
postgres_changes类型的变更事件。
修正后的代码示例:
const projectRef = "[你的项目Ref]"; const anonKey = "[你的anon API密钥]"; // 使用2.0.0版本的协议,兼容性更好 const wsUrl = `wss://${projectRef}.supabase.co/realtime/v1/websocket?apikey=${anonKey}&vsn=2.0.0`; const ws = new WebSocket(wsUrl); ws.onopen = () => { console.log("WebSocket连接已建立"); // 发送符合Phoenix Channels协议的订阅请求 const joinMsg = JSON.stringify({ topic: "realtime:public:MyTable", // 格式:realtime:[schema名称]:[表名称] event: "phx_join", payload: { config: { broadcast: { ack: false }, presence: { key: "" }, filter: { event: "*" } // 指定监听所有事件,可改为INSERT/UPDATE/DELETE } }, ref: "1" // 唯一消息标识,可自定义任意字符串 }); ws.send(joinMsg); console.log("订阅请求已发送"); }; ws.onmessage = (evt) => { const data = JSON.parse(evt.data); console.log("收到消息:", data); // 捕获数据库变更事件 if (data.event === "postgres_changes") { console.log("数据库变更详情:", data.payload); } }; ws.onerror = (err) => { console.error("WebSocket错误:", err); }; ws.onclose = () => { console.log("WebSocket连接已关闭"); };
关键细节说明
- Topic格式:必须严格遵循
realtime:[schema]:[table]的结构,比如监听publicschema下的MyTable,topic就是realtime:public:MyTable。 - 消息结构:所有交互消息都必须是JSON格式,包含四个必填字段:
topic:指定要订阅的通道主题event:操作类型,订阅用phx_join,取消订阅用phx_leavepayload:包含订阅配置(如监听事件类型)ref:唯一消息标识,用于匹配请求与响应
- 协议版本:建议使用
2.0.0,避免与当前Supabase Realtime版本不兼容。
验证方式
运行修正后的代码,向MyTable插入新数据,控制台会输出postgres_changes类型的消息,包含变更的完整数据。
内容的提问来源于stack exchange,提问作者Got Hima
相关产品推荐
相关产品推荐

