靓仔来看 WebSocket 实战教程(Node.js + React)

我是web socket 彭于晏,我喂自己袋盐,请和我双工通信,亲密连接。

随着实时通信需求的增加,WebSocket 在前后端开发中的地位日益提升。本文将基于 Node.js + Express + React + Ant Design 实现一个完整的 WebSocket 聊天室 Demo,包含原生实现与优化建议,适合入门者快速掌握 WebSocket 的实际应用。


🧪 使用场景分析

WebSocket 是一种持久连接协议,允许服务端主动推送消息给客户端,适用于以下场景:

  • 实时聊天 / 通知系统
  • 实时协作编辑(如多人文档)
  • 实时股票、币价、物流追踪
  • 游戏对战通信
  • 实时问答直播弹幕系统

🧠 一句话总结:

如果你有高频率数据更新 + 服务端推送需求,WebSocket 是更优解。


📦 技术栈简介

  • 前端:React + TypeScript + Ant Design
  • 后端:Node.js + Express + ws(WebSocket 原生库)
  • 通信协议:WebSocket 标准协议(可升级为 socket.io

🖥️ 后端实现(Node.js + ws)

安装依赖:

复制代码
bash
复制编辑
npm install ws

后端代码结构:

arduino 复制代码
cpp
复制编辑
├── app.js          // Express 主入口
├── routes/
│   └── ws/index.js // WebSocket 服务初始化

1️⃣ WebSocket 处理逻辑(ws/index.js)

javascript 复制代码
js
复制编辑
// ws/index.js
import { WebSocketServer } from "ws";

const clients = new Set();

export function initWebSocket(server) {
  const wss = new WebSocketServer({ server });

  wss.on("connection", (ws) => {
    console.log("🟢 客户端连接 WebSocket");
    clients.add(ws);

    ws.on("message", (message) => {
      console.log("📩 收到消息:", message.toString());

      // 广播消息
      clients.forEach((client) => {
        if (client.readyState === ws.OPEN) {
          client.send(message.toString());
          client.send(`你好,${message.toString()}`);
        }
      });
    });

    ws.on("close", () => {
      console.log("🔴 客户端断开");
      clients.delete(ws);
    });
  });

  console.log("✅ WebSocket 服务已启动");
}

2️⃣ 启动 Express + WebSocket(app.js)

javascript 复制代码
js
复制编辑
import express from "express";
import http from "http";
import bodyParser from "body-parser";
import cors from "cors";
import { initWebSocket } from "./routes/ws/index.js";

const app = express();
const server = http.createServer(app);

app.use(cors());
app.use(bodyParser.json());
app.use(express.static("public"));

// 启用 WebSocket
initWebSocket(server);

server.listen(8088, () => {
  console.log(`🚀 服务器启动成功:http://localhost:8088`);
});

💻 前端实现(React + Ant Design)

WebSocket 聊天室组件(WS.tsx

ini 复制代码
tsx
复制编辑
import {
  message as AntdMessage,
  Button,
  Card,
  Input,
  List,
  Typography,
} from "antd";
import { useEffect, useRef, useState } from "react";

const { Text } = Typography;
const WS_URL = "ws://localhost:8088/ws";

export default function WS() {
  const [msgList, setMsgList] = useState<string[]>([]);
  const [inputMsg, setInputMsg] = useState("");
  const wsRef = useRef<WebSocket | null>(null);

  useEffect(() => {
    const ws = new WebSocket(WS_URL);
    wsRef.current = ws;

    ws.onopen = () => AntdMessage.success("已连接 WebSocket");
    ws.onmessage = (event) => {
      setMsgList((prev) => [...prev, event.data]);
    };
    ws.onclose = () => AntdMessage.error("WebSocket 已断开");

    return () => {
      ws.close();
    };
  }, []);

  const sendMessage = () => {
    if (!inputMsg.trim()) return AntdMessage.warning("请输入消息内容");
    if (wsRef.current?.readyState === WebSocket.OPEN) {
      wsRef.current.send(inputMsg);
      setInputMsg("");
    } else {
      AntdMessage.error("连接已断开,无法发送");
    }
  };

  return (
    <div style={{ padding: 48, maxWidth: 600, margin: "0 auto" }}>
      <Card title="💬 WebSocket 聊天室 Demo" bordered>
        <List
          size="small"
          dataSource={msgList}
          renderItem={(item, index) => (
            <List.Item key={index}>
              <Text>{item}</Text>
            </List.Item>
          )}
          style={{ maxHeight: 300, overflowY: "auto", marginBottom: 16 }}
        />
        <Input.Group compact>
          <Input
            style={{ width: "calc(100% - 90px)" }}
            value={inputMsg}
            placeholder="请输入消息..."
            onChange={(e) => setInputMsg(e.target.value)}
            onPressEnter={sendMessage}
          />
          <Button type="primary" onClick={sendMessage}>
            发送
          </Button>
        </Input.Group>
      </Card>
    </div>
  );
}

💡 小贴士:在浏览器开发者模式中,在NetWork 得 Socket中,可以实时查看两者客户端与服务端得消息传输内容。


⚙️ 进阶优化建议

虽然 ws 已可实现基本通信,但在实际生产中推荐使用更高级封装,如:

✅ 推荐使用 socket.io 的原因:

优点 说明
自动重连 网络波动后可自动重连
自定义事件 支持 .emit('xxx') / .on('xxx') 事件系统
内建心跳机制 自动处理断线和心跳,连接更稳定
兼容性好 可兼容旧浏览器和 HTTP 长轮询兜底
社区强大 文档丰富、案例多、生态完善

可选替代库:

💡 小贴士:靓仔,具体使用哪个第三方库看你使用场景,我这边上述展示代码,前端代码没有将ws得代码封装到utils,规范化的话请封装到utils使用。


🔚 总结

关键点 描述
是否适合使用 WebSocket 如果是高实时性需求(聊天、直播、推送),非常适合
生产环境推荐 封装库如 socket.io,提升开发体验与稳定性
不适用场景 数据更新不频繁、对实时性要求低的页面,建议仍用 HTTP 轮询或 RESTful

💡 小贴士:使用场景可以跟后端沟通,后端吊毛说用就用呗,我管你这那得。


📎 最后

如果你觉得这篇文章对你有帮助,可以 点赞 + 收藏 + 关注 支持一下,我会持续更新更多【前后端实战 + 可运行 Demo】的技术分享 ❤️!

😩😩😩摸鱼真的好无聊,只能写写水文了。

相关推荐
tang_jian_dong12 分钟前
springboot + vue3 拉取海康视频点位及播放
spring boot·后端·音视频
橘颂TA40 分钟前
【C++】C++11特性的介绍和使用(第三篇)
前端·c++·算法·c++11
程序员爱钓鱼41 分钟前
Go语言实战案例-括号匹配算法
后端·google·go
程序员爱钓鱼1 小时前
Go语言实战案例-判断字符串是否由另一个字符串的字母组成
后端·google·go
郝学胜-神的一滴3 小时前
SpringBoot实战指南:从快速入门到生产级部署(2025最新版)
java·spring boot·后端·程序人生
爷_7 小时前
字节跳动震撼开源Coze平台!手把手教你本地搭建AI智能体开发环境
前端·人工智能·后端
charlee449 小时前
行业思考:不是前端不行,是只会前端不行
前端·ai
Amodoro10 小时前
nuxt更改页面渲染的html,去除自定义属性、
前端·html·nuxt3·nuxt2·nuxtjs
Wcowin10 小时前
Mkdocs相关插件推荐(原创+合作)
前端·mkdocs
伍哥的传说10 小时前
CSS+JavaScript 禁用浏览器复制功能的几种方法
前端·javascript·css·vue.js·vue·css3·禁用浏览器复制