🌐 WebSocket 前端使用简单描述

122 阅读2分钟

🌐 WebSocket 前端使用详解

适用于:React / Vue / 原生JS / Next.js / Taro / UniApp 等前端框架
更新时间:2025-10-07


🧠 一、基本概念

WebSocket 是浏览器原生支持的实时通信协议,用于在客户端与服务器之间建立持续的双向连接

核心对象:

const ws = new WebSocket("ws://localhost:8080");

🚀 二、快速上手示例

1️⃣ 创建连接

const socket = new WebSocket("ws://localhost:8080");

// 连接成功
socket.onopen = () => {
  console.log("✅ WebSocket connected");
  socket.send(JSON.stringify({ type: "join", user: "feipeng" }));
};

// 接收消息
socket.onmessage = (event) => {
  const data = JSON.parse(event.data);
  console.log("📩 Received:", data);
};

// 连接关闭
socket.onclose = () => console.log("❌ WebSocket closed");

// 错误处理
socket.onerror = (error) => console.error("⚠️ WebSocket error:", error);

🧾 三、发送与接收消息

✅ 发送消息

function sendMessage(text) {
  if (socket.readyState === WebSocket.OPEN) {
    socket.send(JSON.stringify({ type: "chat", text }));
  } else {
    console.warn("WebSocket not open yet");
  }
}

✅ 接收消息

socket.onmessage = (event) => {
  const message = JSON.parse(event.data);
  if (message.type === "chat") {
    console.log("💬", message.text);
  } else if (message.type === "system") {
    console.log("🔔", message.notice);
  }
};

🧩 四、心跳检测机制(防止断开)

许多服务器会在空闲时关闭连接,因此需要定期发送“心跳包”维持连接。

✅ 心跳实现

let heartbeatTimer;

function startHeartbeat() {
  heartbeatTimer = setInterval(() => {
    if (socket.readyState === WebSocket.OPEN) {
      socket.send(JSON.stringify({ type: "ping" }));
    }
  }, 30000); // 每30秒一次
}

socket.onmessage = (event) => {
  const msg = JSON.parse(event.data);
  if (msg.type === "pong") return; // 心跳响应不打印
  console.log("📩", msg);
};

🔁 五、断线自动重连

当服务器重启或网络中断时,前端应自动重连。

let socket;
let reconnectTimer;

function connect() {
  socket = new WebSocket("ws://localhost:8080");

  socket.onopen = () => {
    console.log("✅ Connected");
    clearTimeout(reconnectTimer);
    startHeartbeat();
  };

  socket.onmessage = (e) => console.log("📩", e.data);

  socket.onclose = () => {
    console.warn("🔄 Disconnected, retrying...");
    clearInterval(heartbeatTimer);
    reconnectTimer = setTimeout(connect, 2000); // 2秒后重连
  };

  socket.onerror = (err) => {
    console.error("⚠️ Error:", err);
    socket.close();
  };
}

connect();

⚙️ 六、封装为通用模块(原生JS)

export class WebSocketClient {
  constructor(url, onMessage) {
    this.url = url;
    this.onMessage = onMessage;
    this.connect();
  }

  connect() {
    this.ws = new WebSocket(this.url);

    this.ws.onopen = () => {
      console.log("✅ Connected");
      this.startHeartbeat();
    };

    this.ws.onmessage = (e) => this.onMessage(JSON.parse(e.data));

    this.ws.onclose = () => {
      console.log("❌ Disconnected, retrying...");
      clearInterval(this.heartbeat);
      setTimeout(() => this.connect(), 2000);
    };

    this.ws.onerror = () => this.ws.close();
  }

  startHeartbeat() {
    this.heartbeat = setInterval(() => {
      if (this.ws.readyState === WebSocket.OPEN)
        this.ws.send(JSON.stringify({ type: "ping" }));
    }, 30000);
  }

  send(data) {
    if (this.ws.readyState === WebSocket.OPEN)
      this.ws.send(JSON.stringify(data));
  }
}

使用示例:

const client = new WebSocketClient("ws://localhost:8080", (msg) => {
  console.log("📩", msg);
});

client.send({ type: "chat", text: "Hello WebSocket" });

⚛️ 七、React 封装(自定义 Hook)

推荐前端项目直接用这个,支持自动重连 + 状态监听。

import { useEffect, useRef, useState } from "react";

export function useWebSocket(url) {
  const wsRef = useRef(null);
  const [messages, setMessages] = useState([]);
  const [isConnected, setConnected] = useState(false);

  useEffect(() => {
    let reconnectTimer;
    const connect = () => {
      wsRef.current = new WebSocket(url);

      wsRef.current.onopen = () => {
        console.log("✅ Connected to", url);
        setConnected(true);
      };

      wsRef.current.onmessage = (e) => {
        const msg = JSON.parse(e.data);
        setMessages((prev) => [...prev, msg]);
      };

      wsRef.current.onclose = () => {
        console.warn("🔄 Disconnected, retrying...");
        setConnected(false);
        reconnectTimer = setTimeout(connect, 2000);
      };

      wsRef.current.onerror = (err) => {
        console.error("⚠️ WebSocket error:", err);
        wsRef.current.close();
      };
    };

    connect();
    return () => {
      clearTimeout(reconnectTimer);
      wsRef.current?.close();
    };
  }, [url]);

  const send = (data) => {
    if (wsRef.current?.readyState === WebSocket.OPEN)
      wsRef.current.send(JSON.stringify(data));
  };

  return { send, messages, isConnected };
}

使用:

function Chat() {
  const { send, messages, isConnected } = useWebSocket("ws://localhost:8080");

  return (
    <div>
      <h2>WebSocket Chat {isConnected ? "🟢" : "🔴"}</h2>
      <ul>
        {messages.map((m, i) => (
          <li key={i}>{m.text}</li>
        ))}
      </ul>
      <button onClick={() => send({ type: "chat", text: "Hello!" })}>
        Send Message
      </button>
    </div>
  );
}

🧰 八、最佳实践总结

需求推荐实现方式
连接管理自动重连 + 手动关闭
心跳机制ping/pong 保活
消息格式统一 JSON 协议 {type, data}
错误处理onerror + reconnect
跨域使用 wss:// 或在 Nginx 代理
React 项目封装 useWebSocket Hook
Vue 项目封装 useWebSocket Composable

🛠️ 九、调试与测试技巧

  • 浏览器控制台输入:

    new WebSocket("ws://localhost:8080")
    

    即可测试是否能连接。

  • 使用 wscat(Node工具)测试:

    npm install -g wscat
    wscat -c ws://localhost:8080
    

📎 十、可选扩展

功能说明
使用 socket.io简化兼容处理(断线重连内置)
使用 reconnecting-websocket自动重连库
TypeScript 支持定义消息类型接口
Redux/Zustand 状态同步实时消息存储与 UI 同步