IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 网络协议 -> 【nestjs】使用websocket协议通信 -> 正文阅读

[网络协议]【nestjs】使用websocket协议通信

前言

nestjs特别青睐socket.io,文档中关于网关的描述都是以socket.io为例,并且不管是@nestjs/platform-socket.io还是@nestjs/platform-ws的适配器实现都是参考socket.io的,以至于想完整地使用websocket协议进行通信变得难以实现。

WsAdapter遇到的坑

想要使用ws库,需要使用@nestjs/platform-wsWsAdapter,使用方法如下:

// main.ts
// 必须在app.listen方法之前调用
 app.useWebSocketAdapter(new WsAdapter(app));
 await app.listen(3000);

然后开始踩坑。

@SubscribeMessage订阅事件装饰器

在websocket协议里,是没有订阅事件的概念的,这是socket.io里的概念。这里我的解决办法是写死事件名,例如@SubscribeMessage('message')

客户端调用send的方法,服务器无法收到

排除客户端出现问题的可能,测试了一些特定格式的JSON数据是可以的,例如:

{
	"event": "message",
	"data": {
		"test": 123
	}
}

翻了源码,发现是需要按照上述格式的JSON的数据解析的。

// ws-adapter.ts
 const message = JSON.parse(buffer.data);
 const messageHandler = handlers.find(
   handler => handler.message === message.event,
 );
 const { callback } = messageHandler;
 return transform(callback(message.data));

解决方案

@nestjs/platform-ws适配器对传输数据进行了封装,因此我们只要自己写一个适配器就可以解决这个问题。
源码如下:

// src/adapters/ws.adapter.ts
import { WsAdapter as OriginWsAdapter } from '@nestjs/platform-ws';
import { MessageMappingProperties } from '@nestjs/websockets';
import {
  EMPTY,
  filter,
  first,
  fromEvent,
  mergeMap,
  Observable,
  share,
  takeUntil,
} from 'rxjs';
import { CLOSE_EVENT } from '@nestjs/websockets/constants';

enum READY_STATE {
  CONNECTING_STATE = 0,
  OPEN_STATE = 1,
  CLOSING_STATE = 2,
  CLOSED_STATE = 3,
}

export class WsAdapter extends OriginWsAdapter {
  public bindMessageHandlers(
    client: any,
    handlers: MessageMappingProperties[],
    transform: (data: any) => Observable<any>,
  ) {
    const close$ = fromEvent(client, CLOSE_EVENT).pipe(share(), first());
    const source$ = fromEvent(client, 'message').pipe(
      mergeMap((data: any) =>
        this.bindMessageHandler(data.data, handlers, transform).pipe(
          filter((result: any) => result),
        ),
      ),
      takeUntil(close$),
    );
    const onMessage = (response: any) => {
      if (client.readyState !== READY_STATE.OPEN_STATE) {
        return;
      }
      client.send(response);
    };
    source$.subscribe(onMessage);
  }

  bindMessageHandler(
    buffer: string | number | Buffer,
    handlers: MessageMappingProperties[],
    transform: (data: any) => Observable<any>,
  ) {
    try {
      const messageHandler = handlers.find(
      	// 这里的'message'值对应@SubscribeMessage传的值
        (handler) => handler.message === 'message',
      );
      const { callback } = messageHandler;
      return transform(callback(buffer));
    } catch {
      return EMPTY;
    }
  }
}

版本信息

node: 16.13.0
nestjs: 8.4.7

  网络协议 最新文章
使用Easyswoole 搭建简单的Websoket服务
常见的数据通信方式有哪些?
Openssl 1024bit RSA算法---公私钥获取和处
HTTPS协议的密钥交换流程
《小白WEB安全入门》03. 漏洞篇
HttpRunner4.x 安装与使用
2021-07-04
手写RPC学习笔记
K8S高可用版本部署
mySQL计算IP地址范围
上一篇文章      下一篇文章      查看所有文章
加:2022-07-17 16:57:20  更:2022-07-17 16:59:33 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/19 12:21:09-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码