在设置了实时传输(Socket.io或Primus)的Feathers服务器上,事件通道确定哪些连接的客户端发送实时事件以及发送的数据应该如何。
本章介绍:
- 实时连接以及如何访问它们
- 频道使用以及如何检索,加入和离开频道
- 将事件发布到频道
重要提示:如果您不使用实时传输服务器(例如,在制作仅REST API或在客户端上使用Feathers时),则无法使用通道功能。
使用频道的一些示例:
- 实时事件应仅发送给经过身份验证的用户
- 用户只有在加入某个聊天室时才能获得有关消息的更新
- 只有同一组织中的用户才能收到有关其数据更改的实时更新
- 创建新用户时,只应通知管理员
- 当创建,修改或删除用户,非管理员只应接收的用户对象的“安全”的版本(例如,仅
email
,id
和avatar
)
示例
下面的示例显示了生成的channels.js
文件,说明了不同部分如何组合在一起:
module.exports = function(app) {
if(typeof app.channel !== 'function') {
// If no real-time functionality has been configured just return
return;
}
app.on('connection', connection => {
// On a new real-time connection, add it to the anonymous channel
app.channel('anonymous').join(connection);
});
app.on('login', (authResult, { connection }) => {
// connection can be undefined if there is no
// real-time connection, e.g. when logging in via REST
if(connection) {
// Obtain the logged in user from the connection
// const user = connection.user;
// The connection is no longer anonymous, remove it
app.channel('anonymous').leave(connection);
// Add it to the authenticated user channel
app.channel('authenticated').join(connection);
// Channels can be named anything and joined on any condition
// E.g. to send real-time events only to admins use
// if(user.isAdmin) { app.channel('admins').join(connection); }
// If the user has joined e.g. chat rooms
// if(Array.isArray(user.rooms)) user.rooms.forEach(room => app.channel(`rooms/${room.id}`).join(channel));
// Easily organize users by email and userid for things like messaging
// app.channel(`emails/${user.email}`).join(channel);
// app.channel(`userIds/$(user.id}`).join(channel);
}
});
// eslint-disable-next-line no-unused-vars
app.publish((data, hook) => {
// Here you can add event publishers to channels set up in `channels.js`
// To publish only for a specific event use `app.publish(eventname, () => {})`
console.log('Publishing all events to all authenticated users. See `channels.js` and https://docs.feathersjs.com/api/channels.html for more information.'); // eslint-disable-line
// e.g. to publish all service events to all authenticated users use
return app.channel('authenticated');
});
// Here you can also add service specific event publishers
// e.g. the publish the `users` service `created` event to the `admins` channel
// app.service('users').publish('created', () => app.channel('admins'));
// With the userid and email organization from above you can easily select involved users
// app.service('messages').publish(() => {
// return [
// app.channel(`userIds/${data.createdBy}`),
// app.channel(`emails/${data.recipientEmail}`)
// ];
// });
};
连接
连接是表示实时连接的对象。它是同一个对象socket.feathers
在Socket.io和socket.request.feathers
在Primus的中间件。您可以向其添加任何类型的信息,但最值得注意的是,在使用身份验证时,它将包含经过身份验证的用户。默认情况下,它位于connection.user
一旦客户端认证的插座上(通常是通过调用app.authenticate()
上的客户端)。
我们可以connection
通过听取app.on('connection', connection => {})
或访问对象app.on('login', (payload, { connection }) => {})
。
注意:当连接终止时,它将自动从所有通道中删除。
app.on('connection')
app.on('connection', connection => {})
每次建立新的实时连接时都会触发。这是为匿名用户添加通道连接的好地方(如果我们想要向他们发送任何实时更新):
app.on('connection', connection => {
// On a new real-time connection, add it to the
// anonymous channel
app.channel('anonymous').join(connection);
});
app.on('disconnect')
app.on('disconnect', connection => {})
每次实时连接断开时都会触发。这是处理注销之外的断开连接的好地方。断开连接将始终自动保留其所有通道。
app.on('login')
app.on('login', (authResult, params, context) => {})
由AuthenticationService成功登录后发送。
这是添加与用户相关的频道的连接的好地方(例如聊天室,管理员状态等)
app.on('login', (payload, { connection }) => {
// connection can be undefined if there is no
// real-time connection, e.g. when logging in via REST
if(connection) {
// The user attached to this connection
const { user } = connection;
// The connection is no longer anonymous, remove it
app.channel('anonymous').leave(connection);
// Add it to the authenticated user channel
app.channel('authenticated').join(connection);
// Channels can be named anything and joined on any condition `
// E.g. to send real-time events only to admins use
if(user.isAdmin) {
app.channel('admins').join(connection);
}
// If the user has joined e.g. chat rooms
user.rooms.forEach(room => {
app.channel(`rooms/${room.id}`).join(connection);
});
}
});
app.on('logout')
app.on('logout', (authResult, params, context) => {})
由AuthenticationService成功注销后发送。
如果套接字在注销时也没有断开连接,则应该从其通道中删除连接:
app.on('logout', (payload, { connection }) => {
if(connection) {
//When logging out, leave all channels before joining anonymous channel
app.channel(app.channels).leave(connection);
app.channel('anonymous').join(connection);
}
});