You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于ws WebSocket的JWT认证、事件监听等技术问题咨询

关于ws WebSocket库的三个核心问题(附代码修复方案)

嘿,作为经常用ws库开发的人,我来帮你理清这几个问题,先从你卡住的upgrade事件说起!


1. JWT身份认证与upgrade事件未触发的问题

为什么你的upgrade事件没执行?

你的代码里,new WebSocket.Server({ port: 8080 })会让ws库自己创建一个独立的HTTP服务器,而不是复用你传入的server对象。这就导致你给原server绑定的upgrade事件永远不会被触发——因为客户端连接的是8080端口的ws服务器,不是你原来的HTTP服务器。

修复方案+JWT认证实现

把wss的配置改成挂载到传入的server上,去掉port选项,然后在upgrade事件里完成JWT验证:

// File 2 修改后的完整代码
const jwt = require('jsonwebtoken'); // 需要先安装jsonwebtoken:npm i jsonwebtoken

module.exports = function(server) {
 const WebSocket = require('ws');
 // 关键:去掉port,改用server选项挂载到现有HTTP服务器
 const wss = new WebSocket.Server({ server: server });
 
 server.on('upgrade', function(request, socket, head) {
  console.log('Upgraded'); // 现在这个日志会正常打印了!
  
  // 1. 从请求头获取JWT
  const authHeader = request.headers.authorization;
  if (!authHeader || !authHeader.startsWith('Bearer ')) {
    // 认证失败,直接关闭连接
    socket.write('HTTP/1.1 401 Unauthorized\r\n\r\n');
    socket.destroy();
    return;
  }
  
  const token = authHeader.split(' ')[1];
  try {
    // 2. 验证JWT(替换成你的密钥和验证逻辑)
    const decodedUser = jwt.verify(token, 'your-jwt-secret-key');
    
    // 3. 验证通过,完成连接升级
    wss.handleUpgrade(request, socket, head, function(ws) {
      // 把用户信息挂载到ws对象上,后续业务逻辑可以直接用
      ws.user = decodedUser;
      wss.emit('connection', ws, request);
    });
  } catch (err) {
    // 验证失败,拒绝连接
    socket.write('HTTP/1.1 401 Unauthorized\r\n\r\n');
    socket.destroy();
  }
 });
 
 wss.on('connection', function connection(ws) {
  console.log('客户端已连接,用户ID:', ws.user.id);
  ws.on('message', function incoming(message) {
    console.log('received: %s', message);
  });
 });
};

2. 实现类似socket.io的事件类型监听

ws库本身没有内置的事件类型机制,它只提供了基础的message事件来接收所有客户端消息。我们可以通过自定义JSON消息格式来模拟socket.io的事件监听:

服务端实现

wss.on('connection', function connection(ws) {
  ws.on('message', function incoming(rawMessage) {
    try {
      // 把客户端发送的JSON字符串解析成对象
      const message = JSON.parse(rawMessage);
      
      // 根据message.type分发到对应的处理函数
      switch(message.type) {
        case 'chat':
          handleChat(ws, message.data);
          break;
        case 'join-room':
          handleJoinRoom(ws, message.data.roomId);
          break;
        default:
          console.log('未知事件类型:', message.type);
      }
    } catch (err) {
      console.log('消息解析失败:', err);
    }
  });

  // 定义聊天事件的处理逻辑
  function handleChat(ws, content) {
    console.log('收到聊天消息:', content);
    // 给客户端回复一个带类型的消息
    ws.send(JSON.stringify({
      type: 'chat-reply',
      data: `已收到你的消息:${content}`
    }));
  }

  // 定义加入房间的处理逻辑
  function handleJoinRoom(ws, roomId) {
    console.log(`用户${ws.user.id}加入房间${roomId}`);
    // 这里可以实现房间管理、广播等逻辑
  }
});

客户端实现(示例)

const ws = new WebSocket('ws://localhost:3000');

// 发送带事件类型的消息
function sendChatMessage(content) {
  ws.send(JSON.stringify({
    type: 'chat',
    data: content
  }));
}

// 监听服务端的回复事件
ws.onmessage = function(event) {
  const message = JSON.parse(event.data);
  if (message.type === 'chat-reply') {
    console.log('服务端回复:', message.data);
  }
};

3. ws中路径的作用与使用场景

在创建WebSocket.Server时设置path选项,主要有以下几个核心用途:

  • 区分同一端口下的多个WebSocket服务:比如你可以同时运行/ws/chat(聊天服务)和/ws/notifications(通知服务),各自处理不同的业务,不会互相干扰。
  • 与HTTP路由隔离:避免WebSocket请求和普通HTTP API请求混淆,比如你的HTTP服务器有/api/user这样的路由,设置WebSocket路径为/ws可以明确区分两类请求。
  • 精细化权限控制:可以在upgrade事件中通过request.url判断路径,对不同路径的WebSocket连接应用不同的认证或限流规则。

使用示例

// 在同一HTTP服务器上创建两个不同路径的WebSocket服务
const wssChat = new WebSocket.Server({ server: server, path: '/ws/chat' });
const wssNotifications = new WebSocket.Server({ server: server, path: '/ws/notifications' });

// 各自处理连接事件
wssChat.on('connection', (ws) => {
  console.log('聊天服务新连接');
});

wssNotifications.on('connection', (ws) => {
  console.log('通知服务新连接');
});

客户端连接时需要指定对应路径:

const chatWs = new WebSocket('ws://localhost:3000/ws/chat');
const notificationWs = new WebSocket('ws://localhost:3000/ws/notifications');

内容的提问来源于stack exchange,提问作者Jessica

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 11:07:29