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

Socket.IO仅使用WebSocket传输时的连接及认证令牌获取问题

问题解决:纯WebSocket传输代理失败与握手令牌获取方案

一、纯WebSocket传输连接失败的修复

1. 客户端强制指定WebSocket传输

当前客户端未明确限制传输方式,仍默认先尝试轮询,需添加transports: ['websocket']强制仅用WebSocket:

const socket = io.connect("https://localhost:5000",{
  auth: { token: "abc" },
  transports: ['websocket'] // 关键配置:禁用轮询,仅用WebSocket
});

2. 代理配置修正(协议匹配+路径对齐)

代理需与目标服务的HTTPS/WSS协议匹配,否则会出现协议不兼容导致的连接失败:

// REST接口代理
app.use('/endpoint', function (req, res) {
    proxy.web(req, res, { 
        target: { 
            protocol: 'https', 
            host: address.host, 
            port: address.port 
        } 
    })
})

// Socket.IO HTTP握手请求代理
app.use('/socket.io', function (req, res) {
    proxy.web(req, res, { 
        target: { 
            protocol: 'https', // 必须与目标服务协议一致
            host: address.host, 
            port: address.port, 
            path: '/socket.io' 
        } 
    })
})

// WebSocket升级请求代理(对应WSS协议)
server.on('upgrade', function (req, socket, head) {
    proxy.ws(req, socket, head, { 
        target: { 
            protocol: 'wss:', // HTTPS对应WebSocket的wss协议
            host: address.host, 
            port: address.port, 
            path: '/socket.io' 
        } 
    });
});

二、WebSocket握手时获取认证令牌并前置处理

Socket.IO在WebSocket传输模式下,默认会将auth参数序列化为查询参数传递到握手请求中,你可以在代理的upgrade事件中直接解析并验证:

方案1:通过查询参数获取令牌(默认方式)

server.on('upgrade', function (req, socket, head) {
    // 从查询参数中提取token(Socket.IO会自动将auth对象序列化为query参数)
    const token = req.query.token;
    
    // 令牌验证逻辑:验证失败直接拒绝连接
    if (!token || token !== "abc") {
        socket.write('HTTP/1.1 401 Unauthorized\r\n\r\n');
        socket.destroy();
        return;
    }

    // 验证通过后代理至目标服务器
    proxy.ws(req, socket, head, { 
        target: { 
            protocol: 'wss:', 
            host: address.host, 
            port: address.port, 
            path: '/socket.io' 
        } 
    });
});

方案2:通过自定义HTTP Header传递令牌(更安全)

如果希望避免令牌暴露在URL中,可以通过自定义Header传递,需修改客户端和服务端配置:

客户端配置

const socket = io.connect("https://localhost:5000",{
  transports: ['websocket'],
  extraHeaders: {
    'Authorization': 'Bearer abc' // 自定义Header携带令牌
  }
});

目标服务端CORS配置(允许自定义Header)

const io = require('socket.io')(server, {
  cors: {
    origin: "*",
    methods: ["GET", "POST"],
    allowedHeaders: ["Authorization"] // 允许Authorization头
  },
});

代理端获取并验证令牌

server.on('upgrade', function (req, socket, head) {
    const authHeader = req.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];
    
    // 验证逻辑...
    
    proxy.ws(req, socket, head, { /* 目标配置 */ });
});

额外排查点

  • 确保代理服务器与目标服务器的SSL证书一致(自签证书需客户端信任)
  • 检查http-proxy版本是否≥1.0,低版本可能存在WebSocket代理兼容性问题
  • 确认目标服务的端口、域名配置无误,无防火墙拦截

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 17:51:29