API Pusher

Pusher

Pusher 是一个基于 WebSocket 协议的简单可靠平台,提供灵活的发布/订阅消息、在线用户列表(Presence)和身份验证等功能。

Pusher WebSocket API 版本为 7。

数据通过 WebSocket 以包含 UTF-8 编码 JSON 的文本数据双向传输(不支持二进制 WebSocket 帧)。

您可以调用 Ping 方法来测试与服务器的连接。基本上,收到对方的任何消息都表示连接处于活跃状态。在没有任何消息的情况下,任何一方都可以通过发送 ping 消息来检查另一方是否响应,另一方应以 pong 回应。

连接之前,您必须填写以下字段:


Pusher.Cluster := 'eu'; // cluster where your pusher account is located
Pusher.Key := '9c3b7ef25qe97a00116c'; // your pusher api key
Pusher.Name := 'js'; // optional, name of your application
Pusher.Version := '4.1';  // optional, version of your application
Pusher.TLS := True; // if encrypted, set to True
Pusher.Secret := '2dc792e1916ac49e6b3f'; // pusher secret string (needed for private and presence channels)

重要

Pusher 要求 WebSocket 客户端使用前面的字段(key、cluster 等)构建 URL 进行连接,这些字段在将客户端分配给 Pusher 组件时用于构建 URL。因此,为确保 URL 构建正确,请在填写完 Pusher 配置字段后再设置客户端。以下是伪代码示例:

// configure pusher fields

pusher.cluster = ...

pusher.key = ...

// 设置客户端

pusher.client = websocket client

// start connection

websocket client.Active = true;

成功连接后,将触发 OnPusherConnect 事件,并获得以下字段:

发生错误时,将触发 OnPusherError,并提供有关错误的信息。错误可能由 Pusher 响应无效身份验证、无效命令等情况发送。

4000-4099

表示由于 Pusher 关闭连接而发生的错误,使用相同参数尝试重新连接将不会成功。

4000: 应用程序仅接受 SSL 连接,请使用 wss:// 重新连接

4001:应用程序不存在

4003: 应用程序已禁用

4004:应用程序超出连接配额

4005:路径未找到

4006: 版本字符串格式无效

4007:不支持的协议版本

4008:未提供协议版本

4100-4199

表示由于错误导致 Pusher 关闭连接,客户端可在 1 秒或更长时间后重新连接。

4100: 超出容量

4200-4299

表示因连接被 Pusher 关闭而导致的错误,客户端可以立即重新连接。

4200:立即通用重连

4201:未收到 Pong 回复:已向客户端发送 ping,但未收到回复。请参阅 ping 和 pong 消息。

4202:因不活动而关闭:客户端长时间处于非活动状态(目前为 24 小时),且客户端不支持 ping。请升级到较新的 WebSocket 草案或实现第 5 版及以上版本的此协议。

4300-4399

任何其他类型的错误。

4301: 由于速率限制,客户端事件被拒绝

通道

频道是 Pusher 中的基本概念。每个应用程序有多个频道,每个客户端可以选择订阅哪些频道。

频道提供:

强烈建议使用频道过滤数据,而不是通过事件实现。这是因为发布到频道的所有事件都会发送给所有订阅者,无论其绑定的事件类型如何。

频道无需显式创建,按需在客户端请求时实例化。这意味着创建频道非常简单,只需告诉客户端订阅即可。

支持以下类型的频道:

公共频道

公共频道应用于可公开访问的数据,因为它们不需要任何形式的授权即可订阅。

您可以随时订阅和取消订阅频道,无需等待 Pusher 完成连接。

示例:订阅频道"my-channel"。


Delphi
APIPusher.Subscribe('my-channel');

如果订阅成功,OnPusherSubscribe 事件将触发;若发生错误,您将在 OnPusherError 事件中收到消息。

来自已订阅频道的所有消息都将通过 OnPusherEvent 事件接收。

当调用 Publish 方法且通道为公共通道时,组件不使用 WebSocket 协议,而是使用 HTTP 协议并调用 TriggerEvent 方法(WebSocket 协议不允许发布消息)。

私有频道

需要 Indy 10.5.7 或更高版本

当需要以某种方式限制对频道的访问时,应使用私有频道。用户必须获得授权才能订阅私有频道。

示例:订阅频道 "my-private-channel"。


Delphi
APIPusher.Subscribe('my-private-channel', pscPrivateChannel);

如果订阅成功,OnPusherSubscribe 事件将触发;若发生错误,您将在 OnPusherError 事件中收到消息。

来自已订阅频道的所有消息都将通过 OnPusherEvent 事件接收。

Presence 频道

需要 Indy 10.5.7 或更高版本

Presence 频道建立在私有频道的安全性之上,并公开了一个额外功能:感知谁订阅了该频道。这使得在您的应用程序中构建聊天室和"谁在线"类型的功能变得非常容易。想象一下聊天室、文档上的协作者、浏览同一网页的人、游戏中的竞争者等场景。

Presence 频道的订阅方式与私有频道相同,但频道名称必须以 presence- 为前缀。与私有频道一样,系统会向可配置的认证 URL 发起 HTTP 请求,以确定当前用户是否有权限访问该频道。

用户订阅和取消订阅频道的相关信息,随后可通过绑定到在线频道上的事件来访问,当前订阅该频道的用户状态可通过 channel.members 属性获取。

示例:订阅频道 "my-presence-channel"。


APIPusher.Subscribe('my-presence-channel', pscPresenceChannel,
  '{"user_id":"John_Smith","user_info":{"name":"John Smith"}}')

如果订阅成功,OnPusherSubscribe 事件将触发;若发生错误,您将在 OnPusherError 事件中收到消息。

来自已订阅频道的所有消息都将通过 OnPusherEvent 事件接收。

缓存频道

缓存频道会记住上次触发的事件,并将其作为第一个事件发送给新订阅者。

当在缓存频道上触发事件时,Pusher Channels 会缓存此事件。当客户端订阅缓存频道时,如果存在缓存值,则将其作为该频道的第一个事件发送给客户端。此行为帮助开发者无需添加额外逻辑即可提供初始状态。

支持以下缓存频道:

示例:订阅公共缓存频道"my-cache-channel"。


APIPusher.Subscribe('my-cache-channel', pscCacheChannel);

如果订阅成功,OnPusherSubscribe 事件将触发;若发生错误,您将在 OnPusherError 事件中收到消息。

来自已订阅频道的所有消息都将通过 OnPusherEvent 事件接收。

如果订阅缓存频道时没有缓存事件,将引发 OnPusherCacheMiss 事件,提供频道名称。这允许您的应用程序处理无缓存数据可用的情况。

私有加密频道

私有加密通道为消息提供端到端加密。与私有通道一样,它们需要身份验证,但所有数据负载均使用 NaCl secretbox 加密,因此只有授权订阅者才能读取内容。即使是 Pusher 本身也无法解密这些消息。

要使用私有加密频道,您必须在身份验证期间提供 SharedSecret。共享密钥用于加密和解密消息数据。

示例:订阅私有加密频道 "my-encrypted-channel"。


APIPusher.Subscribe('my-encrypted-channel', pscPrivateEncryptedChannel);

还提供私有加密缓存变体,将加密与缓存通道行为相结合:


APIPusher.Subscribe('my-encrypted-cache-channel', pscPrivateEncryptedCacheChannel);

在使用带有私有加密频道的 OnPusherAuthentication 事件时,您可以在响应对象上设置 SharedSecret 属性以提供加密密钥:


procedure OnPusherAuthenticationEvent(Sender: TObject;
  AuthRequest: TsgcWSPusherRequestAuthentication;
  AuthResponse: TsgcWSPusherResponseAuthentication);
begin
  AuthResponse.SharedSecret := 'your-shared-secret-key';
end;

在线状态事件

Presence 频道提供额外的事件,当用户加入或离开频道时通知您的应用程序,并允许您跟踪订阅数量。

OnPusherMemberAdded

当新成员订阅 Presence 频道时触发。提供频道名称、用户 ID 以及加入成员的用户信息。


procedure PUSHERPusherMemberAdded(Sender: TObject;
  Channel, UserId, UserInfo: string);
begin
  Log('Member joined: ' + UserId + ' on ' + Channel);
end;

OnPusherMemberRemoved

当某成员取消订阅 presence 频道时触发。提供频道名称、用户 ID 以及已离开成员的用户信息。


procedure PUSHERPusherMemberRemoved(Sender: TObject;
  Channel, UserId, UserInfo: string);
begin
  Log('Member left: ' + UserId + ' on ' + Channel);
end;

OnPusherSubscriptionCount

当频道上的订阅数量发生变化时触发。提供频道名称和当前订阅者数量。此事件必须在您的 Pusher 仪表板上启用。


procedure PUSHERPusherSubscriptionCount(Sender: TObject;
  Channel: string; SubscriptionCount: Integer);
begin
  Log(Channel + ' has ' + IntToStr(SubscriptionCount) + ' subscribers');
end;

OnPusherCacheMiss

当订阅一个没有缓存事件的缓存频道时触发。提供频道名称。这允许您的应用程序处理没有缓存数据可用的情况,例如从另一个来源获取数据。


procedure PUSHERPusherCacheMiss(Sender: TObject; Channel: string);
begin
  Log('Cache miss on: ' + Channel);
end;

发布消息

您不仅可以从订阅的频道接收消息,还可以向其他已订阅的用户发送消息。

调用 Publish 方法,向频道的所有订阅用户发送消息。

示例:向 "my-channel" 的所有订阅用户发送事件。


APIPusher.Publish('my-event', 'my-channel');

每个客户端(连接)每秒最多发布 10 条消息。超过此速率限制的任何事件将被 Pusher API 拒绝。这不是系统问题,而是客户端问题。如果一个通道中的 100 个客户端都以此速率发送消息,那么每个客户端每秒也需要处理 1,000 条消息!尽管某些现代浏览器可能能够处理这种情况,但这很可能不是一个好主意。

REST API

API 托管在 http://api-CLUSTER.pusher.com,其中 CLUSTER 替换为您自己应用的集群(例如 eu)。

HTTP 状态码用于指示请求的成功或其他状态。以下状态码是常见的:

200 请求成功。正文将包含响应数据的 JSON 哈希值

400 错误:详情见响应体

401 身份验证错误:响应体将包含说明。

403 Forbidden:应用程序已禁用或超出消息配额

已实现以下 REST API 函数。

函数 描述
TriggerEvent 在指定频道上触发新事件。支持可选的 SocketId(用于排除某个客户端)和 Info 参数。
TriggerBatchEvents 在单个 HTTP 请求中触发多个事件。接受事件对象的 JSON 数组。
GetChannels 提供所有活跃频道的列表,支持可选的 FilterByPrefix 和 Info 参数。
GetChannel 提供有关特定通道的信息。支持可选的 Info 参数。
GetUsers 提供连接到某个频道的所有用户列表。
TerminateUserConnections 终止给定用户 ID 的所有连接。

TriggerEvent

在一个或多个频道上触发事件。需要提供事件名称、频道名称和数据有效负载。

参数 描述
aEventName 要触发的事件名称。
aChannel 用于触发事件的频道名称。
aData 事件数据(JSON 字符串)。
aSocketId(可选) 要从接收事件中排除的套接字 ID。可用于防止发送者接收到自己的消息。
aInfo(可选) 响应中要包含的属性逗号分隔列表(例如 "subscription_count")。


// trigger event on a channel
APIPusher.TriggerEvent('my-event', 'my-channel', 'Hello World');

// trigger event excluding the sender
APIPusher.TriggerEvent('my-event', 'my-channel', 'Hello World', '123.456');

// trigger event requesting subscription_count in the response
APIPusher.TriggerEvent('my-event', 'my-channel', 'Hello World', '', 'subscription_count');

TriggerBatchEvents

在单次 API 调用中触发多个事件,比分别为每个事件发送请求更为高效。batch 参数必须是包含事件对象数组的 JSON 字符串,每个对象均包含"channel"、"name"和"data"字段。


APIPusher.TriggerBatchEvents(
  '[{"channel":"my-channel","name":"my-event","data":"hello"},' +
  '{"channel":"my-channel-2","name":"my-event","data":"world"}]');

GetChannels

返回活动频道列表。支持可选参数以过滤结果并请求额外信息。

参数 描述
aFilterByPrefix(可选) 按名称前缀筛选频道(例如,"presence-" 以仅列出 presence 频道)。
aInfo(可选) 响应中包含的属性的逗号分隔列表(例如"user_count")。


// get all channels
APIPusher.GetChannels;

// get only presence channels with user count
APIPusher.GetChannels('presence-', 'user_count');

GetChannel

返回有关特定频道的信息。

参数 描述
aChannel 要获取相关信息的频道名称。
aInfo(可选) 以逗号分隔的要包含的属性列表(例如 "user_count,subscription_count")。


// get channel info
APIPusher.GetChannel('presence-my-channel');

// get channel info with user count
APIPusher.GetChannel('presence-my-channel', 'user_count,subscription_count');

GetUsers

返回连接到 Presence 频道的用户列表。频道名称必须包含完整前缀(例如 "presence-my-channel")。


APIPusher.GetUsers('presence-my-channel');

TerminateUserConnections

终止指定用户建立的所有连接。可用于强制特定用户从所有通道断开连接。用户 ID 必须与用户订阅 Presence 通道时使用的"user_id"匹配。


APIPusher.TerminateUserConnections('1234');

自定义身份验证

Pusher 仅允许订阅私有或存在频道;如果连接提供了身份验证令牌,则可限制访问权限。

您可以使用 OnPusherAuthentication 事件构建自己的认证流程,此事件在订阅消息使用 Pusher 提供的密钥签名之前调用。此事件有 2 个参数,一个包含 SocketId、频道名等字段的认证请求,您的认证服务器可以使用这些字段来决定是否认证请求。以下截图显示了 Pusher 认证流程

当客户端连接到 Pusher 服务器时,将发送 Pusher 提供的 Key,服务器返回一个标识 ID(socket_id)。

当客户端订阅私有(或 presence)频道时,sgcWebSockets 客户端使用 Pusher 提供的 Secret Key 创建包含在订阅消息中的签名。通过 OnPusherAutentication 事件,您可以捕获签名消息所需的字段,实现您自己的身份验证方法,如果成功,则返回签名,该签名将包含在订阅消息中并发送到服务器。

示例:


oClient := TsgcWebSocketClient.Create(nil);
oPusher := TsgcWSAPI_Pusher.Create(nil);
oPusher.Client := oClient;
oPusher.Cluster := 'eu';
Pusher.Name := 'js';
Pusher.Version := '4.1';
Pusher.TLS := True;
Pusher.Key := '9c3b7ef25qe97a00116c';
Pusher.Secret := ''; // the secret key is not known by the client, only by the authentication module

oPusher.OnPusherAuthentication := OnPusherAuthenticationEvent;

procedure OnPusherAuthenticationEvent(Sender: TObject; AuthRequest: TsgcWSPusherRequestAuthentication;
  AuthResponse: TsgcWSPusherResponseAuthentication);
begin
  // if the authentication request is successful return the signature
  if CustomAuthentication(AuthRequest.Channel, AuthRequest.SocketID) then
    AuthResponse.Signature := GetCustomAuthenticationSignature;
end;

签名的格式为:

私有频道:key:HMAC256(SocketID, ChannelName)

Presence 频道:密钥:HMAC256(SocketID, ChannelName, Data)

TsgcWSPusherResponseAuthentication 对象提供以下属性:

属性 描述
密钥 用于计算 HMAC 签名的 Pusher 密钥。若已配置 Pusher.Secret,则预先填充该值。
签名 计算出的身份验证签名。如果留空,组件将使用 Secret 自动计算。
SharedSecret 私有加密频道的共享密钥。订阅 pscPrivateEncryptedChannel 或 pscPrivateEncryptedCacheChannel 时需要。用于消息数据的端到端加密。