Skip to content
Realtime

广播

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 向已连接的客户端发送消息

关于授权,我们会插入一条消息并尝试读取它,然后回滚事务,以验证用户加入通道时是否遵守了他们设置的行级安全(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.

1
import { createClient } from '@supabase/supabase-js'
2
3
const SUPABASE_URL = 'https://<project>.supabase.co'
4
const SUPABASE_KEY = '<sb_publishable_... key>'
5
6
const supabase = createClient(SUPABASE_URL, SUPABASE_KEY)

接收广播消息 #

🌐 Receive Broadcast messages

你可以通过给通道提供回调来接收广播消息。

🌐 You can receive Broadcast messages by providing a callback to the channel.

1
// @noImplicitAny: false
2
import { createClient } from '@supabase/supabase-js'
3
const supabase = createClient('https://<project>.supabase.co', '<sb_publishable_... key>')
4
5
// ---cut---
6
// Join a room/topic. Can be anything except for 'realtime'.
7
const myChannel = supabase.channel('test-channel')
8
9
// Function to log any messages we receive
10
function messageReceived(payload) {
11
console.log(payload)
12
}
13
14
// Subscribe to the Channel
15
myChannel
16
.on(
17
'broadcast',
18
{ event: 'shout' }, // Listen for "shout". Can be "*" to listen to all events
19
(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.

1
import { createClient } from '@supabase/supabase-js'
2
const supabase = createClient('your_project_url', 'your_supabase_api_key')
3
4
// ---cut---
5
const myChannel = supabase.channel('test-channel')
6
7
/**
8
* Sending a message before subscribing will use HTTP
9
*/
10
myChannel
11
.send({
12
type: 'broadcast',
13
event: 'shout',
14
payload: { message: 'Hi' },
15
})
16
.then((resp) => console.log(resp))
17
18
19
/**
20
* Sending a message after subscribing will use WebSockets
21
*/
22
myChannel.subscribe((status) => {
23
if (status !== 'SUBSCRIBED') {
24
return null
25
}
26
27
myChannel.send({
28
type: 'broadcast',
29
event: 'shout',
30
payload: { message: 'Hi' },
31
})
32
})
33
34
/**
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
*/
38
myChannel.send({
39
type: 'broadcast',
40
event: 'cursor-pos',
41
payload: new Uint8Array([1, 2, 3]).buffer,
42
})

来自数据库的广播 #

🌐 Broadcast from the Database

你可以直接使用 realtime.send() 函数从你的数据库发送消息:

🌐 You can send messages directly from your database using the realtime.send() function:

1
select
2
realtime.send(
3
jsonb_build_object('hello', 'world'), -- JSONB Payload
4
'event', -- Event name
5
'topic', -- Topic
6
false -- Public / Private flag
7
);

要从你的数据库广播二进制负载,使用 realtime.send_binary() 函数和 bytea 负载:

🌐 To broadcast a binary payload from your database, use the realtime.send_binary() function with a bytea payload:

1
select
2
realtime.send_binary(
3
'\x012345'::bytea, -- bytea payload
4
'event', -- Event name
5
'topic', -- Topic
6
true -- Private / Public flag (defaults to true)
7
);

相同的公开/私密匹配规则适用:二进制广播只会到达具有相同私密设置的通道。二进制消息只会到达使用 supabase-js 2.91.0supabase-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 payload
2
curl -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'
7
8
# Binary payload
9
curl -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'

广播选项 #

🌐 Broadcast options

你可以在初始化 Supabase 客户端时传入配置选项。

🌐 You can pass configuration options while initializing the Supabase Client.

自发消息 #

🌐 Self-send messages

默认情况下,广播消息只会发送给其他客户端。你可以通过将 Broadcast 的 self 参数设置为 true 来将消息广播回发送者。

1
const myChannel = supabase.channel('room-2', {
2
config: {
3
broadcast: { self: true },
4
},
5
})
6
7
myChannel.on(
8
'broadcast',
9
{ event: 'test-my-messages' },
10
(payload) => console.log(payload)
11
)
12
13
myChannel.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 来确认实时服务器是否已收到你的消息。

1
import { createClient } from '@supabase/supabase-js'
2
const supabase = createClient('your_project_url', 'your_supabase_api_key')
3
4
// ---cut---
5
const myChannel = supabase.channel('room-3', {
6
config: {
7
broadcast: { ack: true },
8
},
9
})
10
11
myChannel.subscribe(async (status) => {
12
if (status !== 'SUBSCRIBED') { return }
13
14
const serverResponse = await myChannel.send({
15
type: 'broadcast',
16
event: 'acknowledge',
17
payload: {},
18
})
19
20
console.log('serverResponse', serverResponse)
21
})

使用这个可以保证在解决 channelD.send 的 promise 之前服务器已经收到消息。如果在创建通道时 ack 配置没有设置为 truechannelD.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.

1
const channel = supabase.channel('test-channel')
2
3
// No need to subscribe to channel
4
5
// JSON payload
6
await channel.httpSend('cursor-pos', { x: Math.random(), y: Math.random() })
7
8
// Binary payload (ArrayBuffer / ArrayBufferView) — sent as application/octet-stream
9
await channel.httpSend('cursor-pos', new Uint8Array([1, 2, 3]).buffer)
10
11
// Remember to clean up the channel
12
13
supabase.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.

1
SELECT realtime.send (
2
'{}'::jsonb, -- JSONB Payload
3
'event', -- Event name
4
'topic', -- Topic
5
FALSE -- Public / Private flag
6
);

广播记录更改 #

🌐 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:

1
CREATE POLICY "authenticated can receive broadcasts"
2
ON "realtime"."messages"
3
FOR SELECT
4
TO authenticated
5
USING ( 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>.

1
CREATE OR REPLACE FUNCTION public.your_table_changes()
2
RETURNS trigger
3
SECURITY DEFINER SET search_path = ''
4
AS $$
5
BEGIN
6
PERFORM realtime.broadcast_changes(
7
'topic:' || NEW.id::text, -- topic
8
TG_OP, -- event
9
TG_OP, -- operation
10
TG_TABLE_NAME, -- table
11
TG_TABLE_SCHEMA, -- schema
12
NEW, -- new record
13
OLD -- old record
14
);
15
RETURN NULL;
16
END;
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.

1
CREATE TRIGGER broadcast_changes_for_your_table_trigger
2
AFTER INSERT OR UPDATE OR DELETE ON public.your_table
3
FOR EACH ROW
4
EXECUTE 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.

1
const gameId = 'id'
2
await supabase.realtime.setAuth() // Needed for Realtime Authorization
3
const changes = supabase
4
.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。
1
const config = {
2
private: true,
3
broadcast: {
4
replay: {
5
since: 1697472000000, // Unix timestamp in milliseconds
6
limit: 10
7
}
8
}
9
}
10
const channel = supabase.channel('main:room', { config })
11
12
// Broadcast callback receives meta field
13
channel.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:

  • 显示聊天室中最新的消息
  • 正在加载体育赛事期间发生的最新事件
  • 确保用户在页面重新加载或网络中断后总能看到最新的事件
  • 高亮网页中最近改变的部分