对于依赖于 实时 客户端-服务器通信的应用程序(例如点对点聊天和社交网络应用程序),发送和监听套接字事件会很快变得不堪重负。Sails 通过引入 **资源丰富的 PubSub** (发布/订阅) 的概念来帮助简化与套接字事件相关的部分复杂性。应用程序中的每个模型都自动配备了资源丰富的 PubSub 方法,这些方法提供了传统的、以数据为中心的接口,用于广播通知和订阅套接字以接收有关单个数据库记录的通知。
如果您的应用程序当前使用的是 蓝图 API,那么您已经在使用资源丰富的 PubSub 方法了!它们嵌入到 Sails 附带的默认蓝图操作中,并在这些操作运行时自动调用,导致请求套接字在获取数据时被订阅,并在数据发生更改时向已订阅的套接字广播消息。(套接字可以通过调用 .subscribe()
或由于先前对 find
或 findOne
蓝图的套接字请求而被订阅。)
即使在编写自定义代码时,也可以手动调用本节中描述的方法,而不是直接使用 sails.sockets.*
方法。将资源丰富的 PubSub 方法视为一种在应用程序中标准化套接字通信接口的方式——这些接口元素可能是房间的名称、作为套接字消息传输的数据模式或套接字事件的名称。这些方法专为以下情况而设计:一个或多个用户界面正在监听套接字事件以与后端保持同步。如果这与您的用例不符,或者您在决定时遇到问题,请不要担心;只需直接调用 sails.sockets.broadcast()
、sails.sockets.join()
或 sails.sockets.leave()
即可。在同一个应用程序中使用任一方法或两种方法都是完全可以接受的。
Sails 公开三种不同的资源丰富的 PubSub (RPS) 方法:.publish()
、.subscribe()
和 .unsubscribe()
。
为了更深入地了解资源丰富的 PubSub 方法,您可能需要先熟悉底层的 sails.sockets.*
方法。因为每个 RPS 方法或多或少只是围绕更简单的 sails.sockets.*
方法的上下文包装器
.publish()
类似于 sails.sockets.broadcast()
.subscribe()
类似于 sails.sockets.join()
.unsubscribe()
类似于 sails.sockets.leave()
这些方法与其在 sails.sockets.*
中的对应方法之间最大的区别在于 RPS 方法公开了更高级别的接口。例如,RPS 方法在幕后为您选择房间名称,并根据模型的标识推断传统的事件名称。
虽然您可以自由地使用任何 JavaScript 库来监听客户端上的套接字事件,但 Sails 提供了自己的套接字客户端,称为 sails.io.js
,作为一种方便的方式从任何支持 Socket.IO 的 Web 浏览器或 Node.js 进程与 Sails 服务器通信。使用 Sails 套接字客户端,监听资源丰富的 PubSub 事件就像以下操作一样简单
io.socket.on('<model identity>', function (msg) {
});
模型标识 通常是模型名称的小写版本,除非它已在模型文件中手动配置。
假设您的应用程序中有一个名为 User
的模型,它具有单个“name”属性。首先,我们将添加一个用于“user”事件的监听器
io.socket.on('user', function(msg){
console.log(msg);
})
只要这些套接字通知的事件名称为“user”,这将记录我们的客户端套接字接收到的任何通知到控制台。但是,在订阅此客户端套接字以接收一个或多个现有 User
记录(在我们的服务器端代码中)之前,我们实际上不会收到这些消息。
如果您的应用程序启用了蓝图 API,那么订阅客户端套接字以接收 User
记录就非常容易了。除了获取数据外,如果 "查找"蓝图操作 是通过 套接字请求 访问的,那么它会自动调用 User.subscribe()
(一个资源丰富的 PubSub 方法)。
例如,假设您编写了一些客户端代码,它向 https://127.0.0.1:1337/user
发送一个套接字 GET
请求
io.socket.get('/user', function(resData) {
console.log(resData);
});
当它运行时,它将命中“查找”蓝图操作,该操作从 Sails 服务器返回当前的用户列表。如果我们发送了一个正常的 HTTP 请求(例如 jQuery.get('/user')
),那么这将是唯一发生的事情。但是,由于我们发送了一个套接字请求,服务器还将我们的客户端套接字订阅到未来关于已返回的用户记录的通知(对 .publish()
的调用)。
有关使用
sails.io.js
客户端发送虚拟请求的更多信息,请参见io.socket.get()
。
与 .subscribe()
不同,RPS .publish()
方法可以从任何地方运行——作为套接字请求、AJAX 请求甚至来自命令行的 cURL 请求的结果触发的控制器操作。或者,.publish()
可以从自定义助手或命令行脚本中调用。
继续上面的示例,如果您要打开一个额外的浏览器窗口并转到以下 URL
/user/create?name=joe
您将在原始窗口的控制台中看到类似以下内容
{
verb: 'created',
id: 1,
data: {
id: 1,
name: 'joe',
createdAt: '2014-08-01T05:50:19.855Z'
updatedAt: '2014-08-01T05:50:19.855Z'
}
}
您在这里看到的是由 "创建"蓝图操作 广播的字典(又名纯 JavaScript 对象)。在蓝图 API 的情况下,此数据的格式是标准化的,但在您的应用程序中,您可以使用 .publish()
来广播您喜欢的任何数据。