Vite搭建一个基于websocket的实时聊天窗口

132 阅读2分钟

WebSocket是一种在单个TCP连接上进行全双工通信的协议。

基于vite 搭建客户端环境:

环境搭建参考地址:https://cn.vitejs.dev/guide/

搭建好环境后在最外层添加vite.config.ts / vite.config.js 文件,文件内具体配置:

import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'

// https://vite.dev/config/
export default defineConfig({
    plugins: [react()],
    // 配置依赖预构建, 只在生产环境中使用
    optimizeDeps: {
      include: process.env.NODE_ENV !== 'production' ? [] : ['antd', 'react'],
    },
  // 配置代理(处理跨域)
  server: {
    host: '0.0.0.0', // 主要是host这个配置,默认是localhost,修改为0.0.0.0之后,局域网内其他设备就可以访问了
    port: 5173, // 设置服务启动端口号
    cors: true, // 允许跨域
    open: true, // 设置服务启动时是否自动打开浏览器
    proxy: {
      '/api': {
        target: 'http://localhost:3001', // 目标服务器地址
        changeOrigin: true, // 是否改变源地址
        rewrite: (path) => path.startsWith('/') ? path : `/${path}` // 根据需要调整重写规则  
      }
    }
  }
})

在App.tsx中添加客户端逻辑:

  • 添加前需先引用antd
import React, { FC, useEffect, useState  } from 'react';
import { Form, Input, Button } from "antd";

const {TextArea } = Input;

const App: FC = () => {

    const [form] = Form.useForm();

    // 必须加 'ws://localhost:3001' ws 协议,后面是开启的服务端接口
    const websocket = new WebSocket('ws://localhost:3001');

    useEffect(() => {

        // 打开事件
        websocket.onopen = function () {
            // 获取当前链接的状态
            // 1 是建立了链接
            console.log("onopen", websocket.readyState);
        };

        // 接收服务器返回的消息
        websocket.onmessage = function (data) {

            // 显示聊天内容的区域
            const chatRoom = document.getElementById('chatRoom');

            // 服务器返回过来的聊天信息
            const chatS = JSON.parse(data.data);

            // 添加到页面上
            chatRoom.innerHTML += `
            <strong>${chatS.userName}:</strong>
            <span>${chatS.chatText}</span>
            <br />
        `
        };
    }, []);


    // 提交表单
    const onFinish = (values) => {

        // 通过 websockte 发送消息
        websocket.send(JSON.stringify(values));

        form.setFieldsValue({ chatText: null}); // 清空对话框
    };

    // 随机生成一个昵称
    const generateNickname = () => {
        const adjectives = ['张', '王', '李', '赵', '刘', '朱', '左', '杨', '陈', '林', '彭', '毛', '郑', '高', '胡', '郭', '梅', '莫', '邓'];
        const nouns = ['飞', '娜', '闪', '龙', '华', '宇', '杰', '强', '涛', '磊', '亮', '艺', '勇', '峰', '豪', '宏', '鹏', '琪', '婷', '丽', '洋'];
        
        // 随机选择一个姓和一个名
        const randomAdjective = adjectives[Math.floor(Math.random() * adjectives.length)];
        const randomNoun = nouns[Math.floor(Math.random() * nouns.length)];
        
        // 拼接成一个昵称
        return randomAdjective + randomNoun;
    };
    
    
     // 客户端断开服务器连接 根据业务场景调用
     // connection.on('close');


    return (
        <>
            <div
                id="chatRoom"
                style={{
                    width:  600,
                    height:  400,
                    border:  '1px solid #ccc',
                    overflowY: 'scroll',
                    marginBottom:  "16px",
                }}
            ></div>
            <Form
                layout="horizontal"
                form={form}
                style={{
                    maxWidth:  600,
                }}
                initialValues={{ userName: generateNickname() }}
                onFinish={onFinish}
            >
                <Form.Item
                    label="用户名(临时模拟用户昵称)"
                    name="userName"
                    rules={[{ required: true }]}
                >
                    <Input  />
                </Form.Item>
                <Form.Item
                    label="对话框"
                    name="chatText"
                    rules={[{ required: true }]}
                >
                    <TextArea placeholder="请输入对话内容" />
                </Form.Item>
                <Form.Item>
                    <Button type="primary" htmlType="submit">
                        发送
                    </Button>
                </Form.Item>
            </Form>
        </>
    );
};


export default App;

Node 搭建服务端:

  • npm init -y 初始化
  • npm install ws 引用websocket
const  websocket = require('websocket').server
const http = require('http');

const httpServer = http.createServer().listen(3001, () => {
    console.log('Server is listening on port 3001: ', 'http://localhost:3001');
});

// 创建 websocket 服务器
const wsServer = new websocket({
    httpServer: httpServer, // 绑定到http服务器
    autoAcceptConnections: false, // 默认情况下接受所有连接
});

const conArr = []; // 存储所有连接(临时使用)

// 处理连接请求
wsServer.on('request', (request) => {

    const connection = request.accept(); // 接受连接
    console.log("connection", connection);

    // 每次接收一个链接,将它存放在数组里面
    conArr.push(connection);

    // 监听消息
    connection.on('message', (message) => {
        // 广播消息
        conArr.forEach((con) => {
            // conArr[i].sendUTF(message.utf8Data); // 发送消息
            con.send(message.utf8Data) // 发送消息
        })
    });
});

// 服务器断开连接,一般由客户端触发,服务端也可根据自身场景去决定是否关闭
// wsServer.onclose = function() {
    console.log("关闭链接")
}
    

效果:

image.png