Nest.js 中的 Socket.io 确认
Posted
技术标签:
【中文标题】Nest.js 中的 Socket.io 确认【英文标题】:Socket.io acknowledgement in Nest.js 【发布时间】:2018-09-11 18:02:44 【问题描述】:我正在尝试在 Nest.js WebSocketGateways 中启用 socket.io 确认回调。
我希望能够发出这个:
socket.emit('event', 'some data', function (response)
//do something
)
并像这样使用消息处理程序:
@SubscribeMessage('event')
onStart(client, data, ack)
//Do stuff
ack('stuff completed');
根据this nestjs/nest GitHub issue 问题,库中不支持它,因此您必须构建自己的 websocket 适配器。我试过了,但不知道该怎么做。我想我需要在bindMessageHandlers
函数中做一些特别的事情,但我的尝试都是徒劳的。
这是框架中捆绑的默认 socket.io 适配器中的bindMessageHandlers
实现:
public bindMessageHandlers(
client,
handlers: MessageMappingProperties[],
process: (data: any) => Observable<any>,
)
handlers.forEach(( message, callback ) =>
Observable.fromEvent(client, message)
.switchMap(data => process(callback(data)))
.filter(result => !!result && result.event)
.subscribe(( event, data ) => client.emit(event, data)),
);
有人对我将如何实现这一点有任何指示吗?
【问题讨论】:
【参考方案1】:在对 NestJS 进行了短暂的研究之后。 这是我的解决方案。
src
├── app.controller.spec.ts
├── app.controller.ts
├── app.module.ts
├── common
│ └── adapters
│ └── ws-adapter.ts
├── events
│ ├── events.gateway.ts
│ └── events.module.ts
└── main.ts
main.ts
文件
import NestFactory from '@nestjs/core';
import AppModule from './app.module';
import WsAdapter from './common/adapters/ws-adapter.ts';
import * as cors from 'cors';
let corsOptions =
origin: 'http://nestjs.test',
credentials: true
async function bootstrap()
const app = await NestFactory.create(AppModule);
app.useWebSocketAdapter(new WsAdapter(3000));
app.use(cors(corsOptions));
await app.listen(4000);
bootstrap();
因为当我们使用 WebSocket Adapter 时,我们不能再使用与 NestJS 应用程序相同的端口了。
common\adapters\ws-adapter.ts
文件
import * as WebSocket from 'ws';
import WebSocketAdapter from '@nestjs/common';
import IoAdapter from '@nestjs/websockets';
import MessageMappingProperties from '@nestjs/websockets';
import Observable from 'rxjs/Observable';
import 'rxjs/add/observable/fromEvent';
import 'rxjs/add/observable/empty';
import 'rxjs/add/operator/switchMap';
import 'rxjs/add/operator/filter';
export class WsAdapter extends IoAdapter
public bindMessageHandlers(
client,
handlers: MessageMappingProperties[],
process: (data: any) => Observable<any>,
)
handlers.forEach(( message, callback ) =>
client.on('event', function (data, ack)
console.log('DATA', data)
ack('woot')
)
Observable.fromEvent(client, message)
.switchMap(data => process(callback(data)))
.filter(result => !!result && result.event)
.subscribe(( event, data ) => client.emit(event, data))
);
我的客户端源代码
socket.emit('event', data: 'some data', function (response)
console.log('RESPONSE', response)
);
socket.on('event', function(data)
console.log('ON EVENT', data);
);
这是我的结果
希望对您有所帮助!
【讨论】:
您的解决方案实际上不起作用,因为我想从网关中的修饰函数运行确认函数。在您的示例中,我必须对适配器中的每个套接字事件进行硬编码,即使这样也行不通,因为我无法访问网关中的服务等。【参考方案2】:更新:Nest 5.0 中添加了对确认的支持。
如果套接字提供程序将多个参数传递给SubscribeMessage
处理程序,则request
参数将是一个包含这些参数的数组。
例如使用默认的socket.io-adapter:
@SubscribeMessage('event')
async onEvent(client, request)
let data = request[0]
let ack = request[1] //the acknowledgement function
一个问题是,如果您不提供确认函数request
将不是一个数组,而只是data
对象。
在我当前的一个项目中,我通过创建一个提取数据和确认函数的辅助函数来解决这个问题,或者创建一个占位符,这意味着我可以随时调用 ack 函数而不考虑它的存在:
export function extractRequest (req: any): data: any, ack?: Function
if (Array.isArray(req))
const [data, ack] = req
return data, ack
else
return data: req, ack: () =>
旧答案: 目前的情况是,如果不修改 Nest 源,这是不可能的。它将在即将发布的 5.0 版本中添加。当它发布时,我会用一个例子来更新这个答案。
来源:https://github.com/nestjs/nest/issues/581
【讨论】:
【参考方案3】:只需使用来自 SubscribeMessage 的 return 语句
// server
@SubscribeMessage('message')
async onMessage(
client: Socket, query: string
)
try
console.log(query)
return 'hello'
catch (e)
// ...
在客户端使用函数作为第三个参数
// client
this.socket.emit('message', query, (res) =>
console.log(res); // should log 'hello'
);
【讨论】:
【参考方案4】:你可以试试这个模块:https://www.npmjs.com/package/nestjs-socket-handlers-with-ack。它在后台调用确认函数,您只需要返回一些值或抛出错误。希望对你有帮助
【讨论】:
以上是关于Nest.js 中的 Socket.io 确认的主要内容,如果未能解决你的问题,请参考以下文章