Skip to content

本地服务消息群发

更新日期 2022-5-19
  • 2022-5-19 更新格式
  • 2022-5-10 创建文档

开发环境

  • macOS 12.3.1
  • nest 8.1.5

本文目标

  • NestJS能做到群发消息
  • 简单html界面控制发送和显示接收的消息

将客户端(网页)发来的消息转发到其它已连接的客户端。

本地服务指的是在本机上运行服务。还没有将服务部署到服务器上。

gateway

我们继续改造Chat1Gateway

首先添加对状态的监听:OnGatewayInitOnGatewayConnectionOnGatewayDisconnect

import { OnGatewayConnection, OnGatewayDisconnect, OnGatewayInit, SubscribeMessage, WebSocketGateway, WebSocketServer } from '@nestjs/websockets';
import { Logger } from '@nestjs/common';

@WebSocketGateway(opt1)
export class Chat1Gateway implements OnGatewayInit, OnGatewayConnection, OnGatewayDisconnect {
  private logger: Logger = new Logger('Chat1Gateway');
  @WebSocketServer()
  server: any;

  afterInit(server: any) {
    this.server = server;
  }

  handleConnection(client: any, ...args: any[]) {
    this.logger.log('新连接', args);
  }

  handleDisconnect(client: any) {
    this.logger.log('断开了连接', client);
  }
  // ...
}
afterInit中,我们获取@WebSocketServer()对象,后面用来群发消息。

监听m2s事件,稍微判断一下发来的消息,然后将消息群发出去。

1
2
3
4
5
6
7
  @SubscribeMessage('m2s')
  onChatMsg(client: any, payload: any): any { // 用户发来的消息 直接转发
    var uid: String = payload.uid;
    if (uid != null && uid.length > 0) { // (1)
      this.server.emit('allMsg', payload);
    }
  }

  1. 这里对uid进行一个简单判断,具体根据实际情况来改

群发消息,使用server的emit方法

this.server.emit('allMsg', payload);

Chat1Gateway完整代码
import { OnGatewayConnection, OnGatewayDisconnect, OnGatewayInit, SubscribeMessage, WebSocketGateway, WebSocketServer } from '@nestjs/websockets';
import { Logger } from '@nestjs/common';

const opt1 = {
    path: '/chat1',
    allowEIO3: true,
    cors: {
        origin: /.*/,
        credentials: true
    }
};

@WebSocketGateway(opt1)
export class Chat1Gateway implements OnGatewayInit, OnGatewayConnection, OnGatewayDisconnect {
private logger: Logger = new Logger('Chat1Gateway');

@WebSocketServer()
server: any;

afterInit(server: any) {
    this.server = server;
}

handleConnection(client: any, ...args: any[]) {
    this.logger.log('新连接', args);
}

handleDisconnect(client: any) {
    this.logger.log('断开了连接', client);
}

@SubscribeMessage('debug')
handleMessage(client: any, payload: any): any { // 用来测试
    this.logger.log('[debug]', payload);
    return {
    event: 'debug an.rustfisher.com',
    data: payload
    };
}

@SubscribeMessage('m2s')
onChatMsg(client: any, payload: any): any { // 用户发来的消息 直接转发
        var uid: String = payload.uid;
        if (uid != null && uid.length > 0) {
        this.server.emit('allMsg', payload);
        }
    }
}

web

修改之前的页面,增加一些控件

html

加入2个input,用来输入用户昵称和消息。 收到的消息放在msg-list

<!DOCTYPE html>

<html>

<head>
    <meta charset="utf-8" />
    <title>Chat - an.rustfisher.com</title>

    <link rel="stylesheet" href="/css/main.css" />
    <script src="https://cdn.socket.io/4.5.0/socket.io.min.js"
        integrity="sha384-7EyYLQZgWBi67fBtVxw60/OWl1kjsfrPFcaU0pp0nAh+i8FD068QogUvg85Ewy1k"
        crossorigin="anonymous"></script>
</head>

<body>

    <h1>测试连接</h1>

    <div>
        <button id="connect">Connect</button>
        <button id="leave">Leave</button>
    </div>

    <div>
        <input id="user-nickname"></input>
        <input id="user-input"></input>
        <button id="send">Send</button>
    </div>

    <ul id="msg-list">

    </ul>


    <script src="/js/index.js"></script>

</body>

</html>

js

index.js完整代码如下

'use strict';

var btnConn = document.querySelector('button#connect');
var btnLeave = document.querySelector('button#leave');
var btnSend = document.querySelector('button#send');
var userNicknameInput = document.querySelector('input#user-nickname');
var userInput = document.querySelector('input#user-input');
var msgList = document.querySelector('ul#msg-list');

var socket = null; // 连接
var uid = null;
var nickname = "RustFisher"; // 昵称

var nameList = ["人参", "卜芥", "儿茶", "八角", "丁香", "刀豆", "三七", "大蓟", "山药", "川乌", "天冬", "天麻", "元胡"];
var nameIndex = Math.floor(Math.random() * nameList.length);
nickname = nameList[nameIndex]; // 随机昵称
userNicknameInput.value = nickname;

// 获取浏览器指纹
const fpPromise = import('https://openfpcdn.io/fingerprintjs/v3')
    .then(FingerprintJS => FingerprintJS.load())

// Get the visitor identifier when you need it.
fpPromise
    .then(fp => fp.get())
    .then(result => {
        // This is the visitor identifier:
        uid = result.visitorId
        const visitorId = result.visitorId
        console.log(visitorId)
    })

function addMsgToList(type, msgBody) {
    var li = document.createElement("li");
    li.setAttribute("id", "newli");
    if (type == 0) {
        li.innerHTML = msgBody;
    } else if (type == 1) {
        li.innerHTML = msgBody.nickname + ": " + msgBody.msg;
    }
    msgList.appendChild(li);
}

// 发起连接
function conn() {
    if (uid == null) {
        console.error('无法连接,还没获取到uid');
        return;
    }
    console.log('try connect');

    const wssUrl = "http://localhost:3000"; // localhost debug

    socket = io(wssUrl, { path: '/chat1' });

    socket.on('connect', function () {
        console.log('连接成功');// 连接状态 连上
        addMsgToList(0, '连接成功');
    });

    socket.on('disconnect', (socket) => {
        console.log('socket已断开', socket);// 连接状态 已断开
        socket = null;
    });

    socket.on('debug', (data) => {
        console.log('[服务器消息][debug], ', data);
    });

    socket.on('allMsg', (data) => {
        console.log('[服务器消息][allMsg], ', data);
        addMsgToList(1, data);
    });

    socket.emit('debug', { uid: uid, msg: "web连接" });
    return true;
}

function disconnect() {
    if (socket) {
        socket.disconnect();
    }
}

function sendMsg() {
    var input = userInput.value;
    if (input == null || input.length == 0) {
        console.warn('请输入文本');
        return;
    }
    if (socket) {
        socket.emit('m2s',
            {
                uid: uid,
                nickname: userNicknameInput.value,
                msg: input
            });
    }
}

btnConn.onclick = conn;
btnLeave.onclick = disconnect;
btnSend.onclick = sendMsg;

FingerprintJS来获取浏览器的信息。可随机产生一些默认的昵称,也可以由用户来输入。

收到服务器消息后,用document.createElement方式添加到列表中。

一些连接状态信息也添加到了消息列表中。

发送消息时,用emit方法,把uid,nickname,msg都传上去。

测试运行

运行NestJS服务后,我们可以用2个浏览器或者2个页面,直接打开index.html,点击connect连接。

然后输入要发送的消息,在其他页面上可以看到效果。

营造出一种类似多人聊天室的感觉。

网页效果

网页效果

参考

示例工程 nest-sample - gitee

作者: rustfisher.com | rf.cs@foxmail.com
示例: AndroidTutorial Gitee, Tutorial Github
本文链接: https://www.an.rustfisher.com/nestjs/simple-chat/transfer-msg-local/
一家之言,仅当抛砖引玉。如有错漏,还请指出。如果喜欢本站的内容,还请支持作者。也可点击1次下方的链接(链接内容与本站无关),谢谢支持服务器。 如有疑问,请与我联系:Android issues - gitee
微信订阅号