Nodejs WebSocket 连通 html 网页(简单案例)

702 阅读5分钟

一、简介

二、node 端基本部署

  • 在入口文件中写入调试即可。

  • 简单版本,只想让 WebSocket 服务器单独运行,可以直接创建一个 WebSocket 服务器,不需要传入 server 对象。

    const WebSocket = require('ws');
    
    // 创建 WebSocket 服务器,不传入 HTTP 服务器
    const wss = new WebSocket.Server({ port: 8080 });
    
    // 监听客户端连接
    wss.on('connection', (ws) => {
      console.log('A new client connected!');
    
      // 监听客户端消息
      ws.on('message', (message) => {
        console.log(`Received message: ${message}`);
    
        // 向客户端发送响应
        ws.send('Message received');
      });
    
      // 向客户端发送初始欢迎消息
      ws.send('Welcome to the WebSocket server!');
    });
    
    console.log('WebSocket server is running on ws://localhost:8080');
    
  • 需要支持 http 服务,也就是额外的接口路由服务,使用默认自带的:

    const WebSocket = require('ws');
    const http = require('http');
    
    // 创建一个 HTTP 服务器,托管静态文件
    const server = http.createServer((req, res) => {
      res.writeHead(200, { 'Content-Type': 'text/html' });
      res.end('<h1>WebSocket Server Running</h1>');
    });
    
    // 创建 WebSocket 服务器,并将其绑定到 HTTP 服务器
    // 这样就可以将 WebSocket 与 server.listen 绑定为一个端口
    const wss = new WebSocket.Server({ server });
    
    // 监听客户端连接
    wss.on('connection', (ws) => {
      console.log('A new client connected!');
    
      // 监听来自客户端的消息
      ws.on('message', (message) => {
        console.log(`Received message: ${message}`);
    
        // 向客户端发送响应
        ws.send('Message received');
      });
    
      // 向客户端发送初始欢迎消息
      ws.send('Welcome to the WebSocket server!');
    });
    
    // 启动 HTTP 服务器并监听端口
    server.listen(8080, () => {
      console.log('Server is running at http://localhost:8080');
    });
    
  • 还有就是使用第三方库,例如 express 之类的库:

    const express = require('express');
    const http = require('http');
    const WebSocket = require('ws');
    
    // 创建 Express 应用
    const app = express();
    
    // 创建 HTTP 服务器并将其与 Express 连接
    const server = http.createServer(app);
    
    // 创建 WebSocket 服务器,并将其绑定到现有的 HTTP 服务器
    const wss = new WebSocket.Server({ server });
    
    // 监听 WebSocket 客户端连接
    wss.on('connection', (ws) => {
      console.log('A new client connected!');
    
      // 监听客户端发送的消息
      ws.on('message', (message) => {
        console.log(`Received message: ${message}`);
        // 向客户端发送响应
        ws.send('Message received');
      });
    
      // 向客户端发送初始欢迎消息
      ws.send('Welcome to the WebSocket server!');
    });
    
    // 在 Express 中定义一些 HTTP 路由
    app.get('/', (req, res) => {
      res.send('<h1>Hello from Express</h1>');
    });
    
    // 启动 HTTP 和 WebSocket 服务器
    server.listen(8080, () => {
      console.log('Server running at http://localhost:8080');
    });
    
  • 选择自己的一种方式配置好后,运行 node 项目即可。

三、客户端基本部署

  • 在现代浏览器中,WebSocket 是原生支持的,不需要引入额外的 CDN 或第三方库。因此,可以直接在客户端的 JavaScript 代码中使用 WebSocket 对象,无需额外的外部依赖。

  • 直接创建一个 index.html 网页,写入代码打开即可,本地用的是 localhost,线上记得根据实际情况进行更换调整。

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>WebSocket Client</title>
    </head>
    <body>
      <h1>WebSocket Test</h1>
      <button id="sendBtn">Send Message to Server</button>
      <div id="response"></div>
    
      <script>
        // 创建 WebSocket 连接到 Node.js WebSocket 服务器
        const socket = new WebSocket('ws://localhost:8080');
    
        // 打开连接时的回调
        socket.addEventListener('open', () => {
          console.log('Connected to WebSocket server');
          socket.send('Hello, server!');
        });
    
        // 监听来自服务器的消息
        // socket.addEventListener('message', (event) => {
        //   const responseDiv = document.getElementById('response');
        //   responseDiv.textContent = 'Server says: ' + event.data;
        //   console.log('Message from server: ' + event.data);
        // });
        
        // 监听来自服务器的消息,这种写法跟上面的写法效果是一样的,其他监听方法也同理
        // 例如上面的 open 监听,下面的 close 都一样,前面加个 on 即可(socket.onclose、socket.onopen)。
        socket.onmessage = (event) => {
          const responseDiv = document.getElementById('response');
          responseDiv.textContent = 'Server says: ' + event.data;
          console.log('Message from server: ' + event.data);
        };
    
        // 监听连接关闭事件
        socket.addEventListener('close', () => {
          console.log('Connection closed');
        });
    
        // 监听连接错误事件
        socket.addEventListener('error', (error) => {
          console.error('WebSocket Error: ' + error);
        });
    
        // 发送消息到服务器按钮
        const sendBtn = document.getElementById('sendBtn');
        sendBtn.addEventListener('click', () => {
          socket.send('Sending message from client');
        });
      </script>
    </body>
    </html>
    

    这样就接通了,就可以根据规则进行使用了。

    image.png

四、心跳模式

  • 不使用心跳机制可能导致的问题:

    • 连接被断开:防火墙、NAT、路由器等设备可能会因长时间无数据流动而断开连接。

    • 无法及时检测断开连接:如果没有心跳机制,可能无法及时得知连接断开。

    • 丢失连接:由于网络问题,可能导致连接丢失,而没有心跳机制无法及时检测并恢复连接。

    • 服务器端或客户端因超时断开连接:服务器可能会因为空闲时间过长而自动断开连接。

      建议:对于长时间运行的 WebSocket 连接,特别是在可能遇到中间网络设备干扰的情况下,使用心跳机制是一个非常好的实践。这可以帮助确保连接活跃、检测断开,并且让应用更加健壮和稳定。

  • node 端

    const express = require('express')
    const http = require('http');
    const path = require('path')
    const app = express()
    const WebSocket = require('ws');
    
    // 创建 HTTP 服务器并将其与 Express 连接
    const server = http.createServer(app);
    // 创建 WebSocket 服务器,并将其绑定到现有的 HTTP 服务器
    const wss = new WebSocket.Server({ server });
    
    // 监听 WebSocket 客户端连接,每个新的连接都是一个独立的处理对象,所以不会造成阻塞
    wss.on('connection', (ws, req) => {
    
      // 获取原始 IP 地址
      const ip = req.socket.remoteAddress;
      // 转换 IPv6 回环地址 (::1) 为 IPv4 的 127.0.0.1
      // ::1 是 IPv6 中的回环地址,等价于 IPv4 中的 127.0.0.1,这表示客户端和服务器运行在同一台机器上(本地连接)。
      const normalizedIp = ip === '::1' ? '127.0.0.1' : ip.replace('::ffff:', '');
      console.log('New client connected from IP:', ip, 'NormalizedIp:', normalizedIp);
    
      // 设置心跳(定时发送 pong)当客户端长时间没有发送 ping 消息时,可以自行发送心跳
      // const heartbeatInterval = setInterval(() => {
      //   // 发送 pong 消息
      //   if (ws.readyState === WebSocket.OPEN) {
      //     ws.send('pong'); // pong 消息
      //   }
      // }, 30000); // 每 30 秒发送一次 ping
    
      // 监听客户端发送的消息
      ws.on('message', (message) => {
        // 如果 message 是 Buffer,转换为字符串
        if (Buffer.isBuffer(message)) {
          message = message.toString();
          console.log('Received message from client:', message);
          // 向客户端发送响应
          // ws.send('Message received')
          // 如果收到 ping 消息,回复 pong 消息
          if (message === 'ping') {
            console.log('Sending pong to client');
            // 响应发送 pong 消息
            ws.send('pong');
          }
        } else {
          console.log('Received message from client:', message);
        }
      })
    
      // 连接关闭时清理定时器
      ws.on('close', () => {
        // clearInterval(heartbeatInterval);
        console.log('Client disconnected')
      })
    
      // 向客户端发送初始欢迎消息
      ws.send('Welcome to the WebSocket server!')
    })
    
    // 设置静态页面,默认就是 '/' 路由
    app.use(express.static(path.join(__dirname, 'public')));
    
    // 处理未匹配到的路由,返回 404 页面
    app.use((req, res) => {
      res.status(404).sendFile(path.join(__dirname, 'public/404.html'))
    })
    
    // 启动 HTTP 和 WebSocket 服务器
    server.listen(8080, () => {
      console.log('Server running at http://localhost:8080');
    });
    
  • 客户端

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Document</title>
      <style>
        html, body {
          width: 100%;
          height: 100%;
        }
        html, body, ul, li, dl, dt, dd {
          margin: 0;
          padding: 0;
        }
        .container {
          width: 100%;
          height: 100%;
          display: flex;
          align-items: center;
          justify-content: center;
        }
      </style>
    </head>
    <body>
      <div class="container">
        <!-- <button id="send">发送消息</button> -->
        <h1>WebSocket Test</h1>
        <button id="sendBtn">Send Message to Server</button>
        <div id="response"></div>
    
        <script>
          // 创建 WebSocket 连接到服务器
          const socket = new WebSocket('ws://localhost:8080');
    
          // 当连接建立时
          socket.onopen = () => {
            console.log('Connected to the WebSocket server');
    
            // 设置心跳(每隔 30 秒发送一次 ping)
            setInterval(() => {
              if (socket.readyState === WebSocket.OPEN) {
                socket.send('ping'); // 向服务器发送 ping
              }
            }, 30000);
          };
    
          // 处理消息
          socket.onmessage = (event) => {
            const responseDiv = document.getElementById('response');
            responseDiv.textContent = 'Server says: ' + event.data;
            console.log('Message from server: ' + event.data);
    
            // 如果收到 pong 响应,代表服务器响应了心跳
            if (event.data === 'pong') {
              console.log('Received pong from server');
            }
          };
    
          // 连接关闭时的回调
          socket.onclose = () => {
            console.log('Disconnected from the WebSocket server');
          };
    
          // 发送消息到服务器按钮
          const sendBtn = document.getElementById('sendBtn');
          sendBtn.addEventListener('click', () => {
            socket.send('Sending message from client');
          });
        </script>
      </div>
    </body>
    </html>