广播
Send low-latency messages using the client libs, REST, or your Database.
你可以使用实时广播在用户之间发送低延迟消息。消息可以通过客户端库、REST API 或直接从你的数据库发送。
🌐 You can use Realtime Broadcast to send low-latency messages between users. Messages can be sent using the client libraries, REST APIs, or directly from your database.
广播是如何运作的 #
🌐 How Broadcast works
广播的工作方式会根据你使用的通道而变化:
🌐 The way Broadcast works changes based on the channel you are using:
- REST API:接收 HTTP 请求,然后通过 WebSocket 向连接的客户端发送消息
- 客户端库:通过 WebSocket 向服务器发送消息,然后服务器通过 WebSocket 向已连接的客户端发送消息
- 数据库:在
realtime.messages中添加一个新条目,其中逻辑复制设置为监听更改,然后通过 WebSocket 向已连接的客户端发送消息
公共标志(realtime.send(payload, event, topic, is_private) 中的最后一个参数)只影响谁可以订阅该主题,而不影响谁可以从数据库中读取消息。
🌐 The public flag (the last argument in realtime.send(payload, event, topic, is_private)) only affects who can subscribe to the topic not who can read messages from the database.
- 公开(
false)→ 任何人都可以在不认证的情况下订阅该主题 - 私有 (
true) → 只有经过认证的客户端才能订阅该主题
不管是公共的还是私有的,实时服务都会以经过身份验证的 Supabase 管理员角色连接到你的数据库。
🌐 Regardless if it's public or private, the Realtime service connects to your database as the authenticated Supabase Admin role.
关于授权,我们会插入一条消息并尝试读取它,然后回滚事务,以验证用户加入通道时是否遵守了他们设置的行级安全(RLS)策略,但这条消息不会发送给用户。你可以在授权中查看更多信息。
🌐 For Authorization, we insert a message and try to read it, and rollback the transaction to verify that the Row Level Security (RLS) policies set by the user are being respected by the user joining the channel, but this message isn't sent to the user. You can read more about it in Authorization.
订阅消息 #
🌐 Subscribe to messages
你可以使用 Supabase 客户端库来接收广播消息。
🌐 You can use the Supabase client libraries to receive Broadcast messages.
初始化客户端 #
🌐 Initialize the client
从项目的 Connect 对话框 获取项目的 URL 和密钥。
🌐 Get the Project URL and key from the project's Connect dialog.
API 密钥的更改
Supabase 改变了密钥的工作方式,以提升项目安全性和开发者体验。你可以在 GitHub 上阅读完整公告。
🌐 Supabase has changed the way keys work to improve project security and developer experience. You can read the full announcement on GitHub.
它们将在2026年底被弃用,你现在应该改用可发布的(sb_publishable_xxx)和秘密的(sb_secret_xxx)密钥。
在大多数情况下,你可以从项目的 连接 对话框获得密钥,但如果你想要特定的密钥,可以在仪表板的设置 > API 密钥部分找到它们。
🌐 In most cases, you can get keys from the Project's Connect dialog, but if you want a specific key, you can find them in the Settings > API Keys section of the Dashboard.
- 对于新密钥,打开 API 密钥 标签,如果你还没有可发布的密钥,点击 创建新 API 密钥,然后从 可发布密钥 部分复制数值用于客户端操作。对于服务器端操作,则从 密钥 部分复制数值。
- 对于旧版密钥,从 Legacy API Keys 标签中复制
anon密钥用于客户端操作,service_role密钥用于服务器端操作。
1import { createClient } from '@supabase/supabase-js'23const SUPABASE_URL = 'https://<project>.supabase.co'4const SUPABASE_KEY = '<sb_publishable_... key>'56const supabase = createClient(SUPABASE_URL, SUPABASE_KEY)接收广播消息 #
🌐 Receive Broadcast messages
你可以通过给通道提供回调来接收广播消息。
🌐 You can receive Broadcast messages by providing a callback to the channel.
二进制负载(ArrayBuffer / ArrayBufferView)会自动从 supabase-js 2.91.0 和 supabase-swift 2.44.0 接收。在旧版本的 SDK 中,二进制消息会被静默丢弃,根本不会到达回调。
🌐 Binary payloads (ArrayBuffer / ArrayBufferView) are received automatically from supabase-js 2.91.0 and supabase-swift 2.44.0. On older SDK versions, binary messages are silently dropped and never reach the callback.
1// @noImplicitAny: false2import { createClient } from '@supabase/supabase-js'3const supabase = createClient('https://<project>.supabase.co', '<sb_publishable_... key>')45// ---cut---6// Join a room/topic. Can be anything except for 'realtime'.7const myChannel = supabase.channel('test-channel')89// Function to log any messages we receive10function messageReceived(payload) {11 console.log(payload)12}1314// Subscribe to the Channel15myChannel16 .on(17 'broadcast',18 { event: 'shout' }, // Listen for "shout". Can be "*" to listen to all events19 (payload) => messageReceived(payload)20 )21 .subscribe()发送消息 #
🌐 Send messages
使用客户端库进行广播 #
🌐 Broadcast using the client libraries
你可以使用 Supabase 客户端库来发送广播消息。
🌐 You can use the Supabase client libraries to send Broadcast messages.
广播负载可以通过 WebSocket 以二进制形式(例如 ArrayBuffer 或 ArrayBufferView,比如 Uint8Array)从 supabase-js 2.91.0 和 supabase-swift 2.44.0 发送。发送到运行旧版本 SDK 的客户端的二进制负载会被静默丢弃,永远不会通过 WebSocket 到达。Dart、Kotlin 和 Python 客户端还不支持二进制负载。
🌐 Broadcast payloads can be binary (ArrayBuffer or ArrayBufferView, e.g. Uint8Array) over WebSocket from supabase-js 2.91.0 and supabase-swift 2.44.0. Binary payloads sent to clients running older SDK versions are silently dropped and never arrive over the WebSocket. The Dart, Kotlin, and Python clients don't support binary payloads yet.
1import { createClient } from '@supabase/supabase-js'2const supabase = createClient('your_project_url', 'your_supabase_api_key')34// ---cut---5const myChannel = supabase.channel('test-channel')67/**8 * Sending a message before subscribing will use HTTP9 */10myChannel11 .send({12 type: 'broadcast',13 event: 'shout',14 payload: { message: 'Hi' },15 })16 .then((resp) => console.log(resp))171819/**20 * Sending a message after subscribing will use WebSockets21 */22myChannel.subscribe((status) => {23 if (status !== 'SUBSCRIBED') {24 return null25 }2627 myChannel.send({28 type: 'broadcast',29 event: 'shout',30 payload: { message: 'Hi' },31 })32})3334/**35 * The payload can be binary (ArrayBuffer / ArrayBufferView) from supabase-js 2.91.0.36 * Receivers on older SDK versions will not get the message.37 */38myChannel.send({39 type: 'broadcast',40 event: 'cursor-pos',41 payload: new Uint8Array([1, 2, 3]).buffer,42})来自数据库的广播 #
🌐 Broadcast from the Database
使用数据库通过广播发送的所有消息都会存储在 realtime.messages 表中,并会在 3 天后删除。
🌐 All the messages sent using Broadcast from the Database are stored in realtime.messages table and will be deleted after 3 days.
你可以直接使用 realtime.send() 函数从你的数据库发送消息:
🌐 You can send messages directly from your database using the realtime.send() function:
1select2 realtime.send(3 jsonb_build_object('hello', 'world'), -- JSONB Payload4 'event', -- Event name5 'topic', -- Topic6 false -- Public / Private flag7 );数据库中的 realtime.send() 函数包含一个标志,用来决定广播是私有的还是公开的,客户端通道也有相同的配置。为了让广播正确运行,这些设置必须匹配。公开广播只会到达公开通道,私有广播只会到达私有通道。
🌐 The realtime.send() function in the database includes a flag that determines whether the broadcast is private or public, and client channels also have the same configuration. For broadcasts to work correctly, these settings must match. A public broadcast only reaches public channels and a private broadcast only reaches private channels.
默认情况下,所有数据库广播都是私密的,这意味着客户端必须进行身份验证才能接收它们。如果数据库发送了公共消息,但客户端订阅了一个私密通道,消息就不会被传送,因为私密通道只接受已签名、经过身份验证的消息。
🌐 By default, all database broadcasts are private, meaning clients must authenticate to receive them. If the database sends a public message but the client subscribes to a private channel, the message is not delivered because private channels only accept signed, authenticated messages.
要从你的数据库广播二进制负载,使用 realtime.send_binary() 函数和 bytea 负载:
🌐 To broadcast a binary payload from your database, use the realtime.send_binary() function with a bytea payload:
1select2 realtime.send_binary(3 '\x012345'::bytea, -- bytea payload4 'event', -- Event name5 'topic', -- Topic6 true -- Private / Public flag (defaults to true)7 );相同的公开/私密匹配规则适用:二进制广播只会到达具有相同私密设置的通道。二进制消息只会到达使用 supabase-js 2.91.0 和 supabase-swift 2.44.0 或更高版本的客户端;旧版本客户端会默默丢弃它们。
🌐 The same public/private matching rule applies: a binary broadcast only reaches channels with the same private setting. Binary messages only reach clients on supabase-js 2.91.0 and supabase-swift 2.44.0 or later; older clients silently drop them.
你可以使用 realtime.broadcast_changes() 辅助函数在记录创建、更新或删除时广播消息。想了解更多详情,请阅读 订阅数据库更改。
🌐 You can use the realtime.broadcast_changes() helper function to broadcast messages when a record is created, updated, or deleted. For more details, read Subscribing to Database Changes.
使用 REST API 进行广播 #
🌐 Broadcast using the REST API
你可以通过向 Realtime 服务器发送 HTTP 请求来发送单条广播消息。端点在路径中嵌入了主题和事件,而 Content-Type 头则决定了负载类型:
🌐 You can send a single Broadcast message by making an HTTP request to Realtime servers. The endpoint embeds the topic and event in the path, and the Content-Type header determines the payload type:
application/json— JSON 数据负载application/octet-stream— 二进制负载
把 ?private=true 加到广播到私有通道。
🌐 Add ?private=true to broadcast to a private channel.
1# JSON payload2curl -v \3-H 'apikey: <SUPABASE_TOKEN>' \4-H 'Content-Type: application/json' \5--data-raw '{ "test": "test" }' \6'https://<PROJECT_REF>.supabase.co/realtime/v1/api/broadcast/test/events/event'78# Binary payload9curl -v \10-H 'apikey: <SUPABASE_TOKEN>' \11-H 'Content-Type: application/octet-stream' \12--data-binary @payload.bin \13'https://<PROJECT_REF>.supabase.co/realtime/v1/api/broadcast/test/events/event?private=true'要在一次请求中发送多条消息,批量端点 POST /realtime/v1/api/broadcast 仍然可用。它接受一个包含 messages 数组的 JSON 请求体(仅限 JSON 负载):
🌐 To send multiple messages in a single request, the batch endpoint POST /realtime/v1/api/broadcast is still available. It accepts a JSON body with a messages array (JSON payloads only):
1curl -v \2-H 'apikey: <SUPABASE_TOKEN>' \3-H 'Content-Type: application/json' \4--data-raw '{5 "messages": [6 {7 "topic": "test",8 "event": "event",9 "payload": { "test": "test" }10 }11 ]12}' \13'https://<PROJECT_REF>.supabase.co/realtime/v1/api/broadcast'广播选项 #
🌐 Broadcast options
你可以在初始化 Supabase 客户端时传入配置选项。
🌐 You can pass configuration options while initializing the Supabase Client.
自发消息 #
🌐 Self-send messages
默认情况下,广播消息只会发送给其他客户端。你可以通过将 Broadcast 的 self 参数设置为 true 来将消息广播回发送者。
1const myChannel = supabase.channel('room-2', {2 config: {3 broadcast: { self: true },4 },5})67myChannel.on(8 'broadcast',9 { event: 'test-my-messages' },10 (payload) => console.log(payload)11)1213myChannel.subscribe((status) => {14 if (status !== 'SUBSCRIBED') { return }15 myChannel.send({16 type: 'broadcast',17 event: 'test-my-messages',18 payload: { message: 'talking to myself' },19 })20})确认消息 #
🌐 Acknowledge messages
你可以通过将 Broadcast 的 ack 设置为 true 来确认实时服务器是否已收到你的消息。
1import { createClient } from '@supabase/supabase-js'2const supabase = createClient('your_project_url', 'your_supabase_api_key')34// ---cut---5const myChannel = supabase.channel('room-3', {6 config: {7 broadcast: { ack: true },8 },9})1011myChannel.subscribe(async (status) => {12 if (status !== 'SUBSCRIBED') { return }1314 const serverResponse = await myChannel.send({15 type: 'broadcast',16 event: 'acknowledge',17 payload: {},18 })1920 console.log('serverResponse', serverResponse)21})使用这个可以保证在解决 channelD.send 的 promise 之前服务器已经收到消息。如果在创建通道时 ack 配置没有设置为 true,channelD.send 返回的 promise 会立即解决。
🌐 Use this to guarantee that the server has received the message before resolving channelD.send's promise. If the ack config is not set to true when creating the channel, the promise returned by channelD.send will resolve immediately.
使用 REST 调用发送消息 #
🌐 Send messages using REST calls
你也可以通过向实时服务器发送 HTTP 请求来发送广播消息。当你想从服务器或客户端发送消息,而不必先建立 WebSocket 连接时,这非常有用。
🌐 You can also send a Broadcast message by making an HTTP request to Realtime servers. This is useful when you want to send messages from your server or client without having to first establish a WebSocket connection.
channel.httpSend() 总是使用 REST API,无论 WebSocket 连接状态如何,并且从 Supabase JavaScript 客户端 2.107.0 及更高版本可用。ArrayBuffer 和 ArrayBufferView(例如 Uint8Array)的负载以 application/octet-stream 形式发送;所有其他负载都是 JSON 编码的。
1const channel = supabase.channel('test-channel')23// No need to subscribe to channel45// JSON payload6await channel.httpSend('cursor-pos', { x: Math.random(), y: Math.random() })78// Binary payload (ArrayBuffer / ArrayBufferView) — sent as application/octet-stream9await channel.httpSend('cursor-pos', new Uint8Array([1, 2, 3]).buffer)1011// Remember to clean up the channel1213supabase.removeChannel(channel)从你的数据库触发广播消息 #
🌐 Trigger broadcast messages from your database
它是怎么运作的 #
🌐 How it works
广播更改让你可以从数据库触发消息。为了实现这一点,Realtime 会直接使用对 realtime.messages 表的发布来读取你的预写日志(WAL)文件。每当有新的插入发生时,消息就会发送给连接的用户。
🌐 Broadcast Changes allows you to trigger messages from your database. To achieve it, Realtime directly reads your Write-Ahead Log (WAL) file using a publication against the realtime.messages table. Whenever a new insert occurs, a message is sent to connected users.
它使用按天分区的表,这使得通过删除这个分区表的物理表来高效地删除你之前的消息成为可能。超过三天的表会被删除。
🌐 It uses partitioned tables per day, which allows performant deletion of your previous messages by dropping the physical tables of this partitioned table. Tables older than 3 days are deleted.
从数据库进行广播的工作方式类似客户端广播,使用 WebSockets 发送 JSON 数据包。默认情况下,需要并启用了 实时授权 来保护你的数据。
🌐 Broadcasting from the database works like a client-side broadcast, using WebSockets to send JSON payloads. Realtime Authorization is required and enabled by default to protect your data.
广播更改提供了两个功能来帮助你发送消息:
🌐 Broadcast Changes provides two functions to help you send messages:
realtime.send()在不使用特定格式的情况下向realtime.messages插入消息。realtime.broadcast_changes()插入一条带有必填字段的消息,用于向客户端发送数据库变更。这可以帮助你在表上设置触发器来发出变更通知。
从你的数据库广播一条消息 #
🌐 Broadcasting a message from your database
realtime.send() 函数提供了最大的灵活性,因为它允许你从数据库广播消息而无需特定格式。这让你可以使用数据库广播来发送那些不一定与 Postgres 行变化的形式相关的消息。
🌐 The realtime.send() function provides the most flexibility by allowing you to broadcast messages from your database without a specific format. This allows you to use database broadcast for messages that aren't necessarily tied to the shape of a Postgres row change.
1SELECT realtime.send (2 '{}'::jsonb, -- JSONB Payload3 'event', -- Event name4 'topic', -- Topic5 FALSE -- Public / Private flag6);广播记录更改 #
🌐 Broadcast record changes
设置实时授权 #
🌐 Setup realtime authorization
实时授权是必需的,并且默认启用。要允许你的用户收听来自主题的消息,请创建一个 RLS 策略:
🌐 Realtime Authorization is required and enabled by default. To allow your users to listen to messages from topics, create an RLS policy:
1CREATE POLICY "authenticated can receive broadcasts"2ON "realtime"."messages"3FOR SELECT4TO authenticated5USING ( true );阅读 实时授权 了解如何设置更具体的策略。
🌐 Read Realtime Authorization to learn how to set up more specific policies.
设置触发函数 #
🌐 Set up trigger function
首先,设置一个触发器函数,使用 realtime.broadcast_changes() 函数在触发时插入一个事件。这个事件会包括触发它的模式、表、操作和字段变化的数据。
🌐 First, set up a trigger function that uses the realtime.broadcast_changes() function to insert an event whenever it is triggered. The event is set up to include data on the schema, table, operation, and field changes that triggered it.
在这个例子中,你将向名为 topic:<record_id> 的主题广播事件。
🌐 For this example, you're going broadcast events to a topic named topic:<record_id>.
1CREATE OR REPLACE FUNCTION public.your_table_changes()2RETURNS trigger3SECURITY DEFINER SET search_path = ''4AS $$5BEGIN6 PERFORM realtime.broadcast_changes(7 'topic:' || NEW.id::text, -- topic8 TG_OP, -- event9 TG_OP, -- operation10 TG_TABLE_NAME, -- table11 TG_TABLE_SCHEMA, -- schema12 NEW, -- new record13 OLD -- old record14 );15 RETURN NULL;16END;17$$ LANGUAGE plpgsql;使用的 Postgres 本地触发器特殊变量有:
🌐 The Postgres native trigger special variables used are:
TG_OP- 触发该函数的操作TG_TABLE_NAME- 触发器触发的表TG_TABLE_SCHEMA- 导致触发器被调用的表的模式NEW- 更改后的记录OLD- 更改前的记录
你可以在这个指南中了解更多关于它们的信息。
🌐 You can read more about them in this guide.
设置触发器 #
🌐 Set up trigger
接下来,设置一个触发器,让函数在目标表有更改时运行。
🌐 Next, set up a trigger so the function runs whenever your target table has a change.
1CREATE TRIGGER broadcast_changes_for_your_table_trigger2AFTER INSERT OR UPDATE OR DELETE ON public.your_table3FOR EACH ROW4EXECUTE FUNCTION your_table_changes ();如你所见,它会广播所有操作,所以我们的用户在 public.your_table 中的记录被插入、更新或删除时都会收到事件。
🌐 As you can see, it will be broadcasting all operations so our users will receive events when records are inserted, updated or deleted from public.your_table .
在客户端监听 #
🌐 Listen on client side
最后,客户端需要设置以监听主题 topic:<record id> 来接收事件。
🌐 Finally, client side will requires to be set up to listen to the topic topic:<record id> to receive the events.
1const gameId = 'id'2await supabase.realtime.setAuth() // Needed for Realtime Authorization3const changes = supabase4 .channel(`topic:${gameId}`)5 .on('broadcast', { event: 'INSERT' }, (payload) => console.log(payload))6 .on('broadcast', { event: 'UPDATE' }, (payload) => console.log(payload))7 .on('broadcast', { event: 'DELETE' }, (payload) => console.log(payload))8 .subscribe()重播 #
🌐 Broadcast replay
它是怎么运作的 #
🌐 How it works
广播重播让私有通道可以查看之前发送的消息。只有通过 从数据库广播 发布的消息可以重播。
🌐 Broadcast Replay enables private channels to access messages that were sent earlier. Only messages published via Broadcast From the Database are available for replay.
你可以用以下选项来配置重播:
🌐 You can configure replay with the following options:
since(必填):以毫秒为单位的纪元时间戳(例如,1697472000000),指定应从何时开始检索消息的最早时间点。limit(可选):要返回的消息数量。必须是正整数,最大值为25。
消息会存储在按天分的分区里,超过72小时的分区会被删除。因为是整天整天地删除,所以一条消息至少能保留72小时,最多能保留4天,具体取决于发送的时间。如果把 since 设置得比保留窗口还早,也无法找回已删除的消息。详情请看 实时限制。
🌐 Messages are stored in daily partitions, and partitions older than 72 hours are dropped. Because whole days are removed at once, a message stays available for at least 72 hours and at most 4 days, depending on the time of day it was sent. Setting since further back than the retained window does not recover deleted messages. See Realtime Limits for details.
这目前只在 Supabase JavaScript 客户端版本 2.74.0 及以后可用。
1const config = {2 private: true,3 broadcast: {4 replay: {5 since: 1697472000000, // Unix timestamp in milliseconds6 limit: 107 }8 }9}10const channel = supabase.channel('main:room', { config })1112// Broadcast callback receives meta field13channel.on('broadcast', { event: 'position' }, (payload) => {14 if (payload?.meta?.replayed) {15 console.log('Replayed message: ', payload)16 } else {17 console.log('This is a new message', payload)18 }19 // ...20})21.subscribe()什么时候使用广播回放 #
🌐 When to use Broadcast replay
Broadcast Replay 的一些常见使用场景包括:
🌐 A few common use cases for Broadcast Replay include:
- 显示聊天室中最新的消息
- 正在加载体育赛事期间发生的最新事件
- 确保用户在页面重新加载或网络中断后总能看到最新的事件
- 高亮网页中最近改变的部分