无法访问底层HTTP服务器时,如何在Express中间件中实现WebSocket升级?
在Express中间件中处理WebSocket升级(无法访问底层HTTP服务器)
背景需求
我正在编写一个Express中间件,需要处理多个端点——大部分是纯HTTP端点,少数特殊端点需要通过WebSocket实现双向通信。
常规实现(可访问底层HTTP服务器时)
当能直接操作底层HTTP服务器时,标准实现可以正常工作:
import http from 'http'; const server = http.createServer(app); app.listen = function serverListen(...args) { return server.listen(...args); }; const wss = new WebSocketServer({ server: server }); wss.on('connection', (ws) => { ws.on('message', (message) => { console.log('Received:', message); ws.send('Message received: ' + message); }); }); server.on('upgrade', function upgrade(request, socket, head) { wss.handleUpgrade(request, socket, head, function done(ws) { wss.emit('connection', ws, request); }); });
这里HTTP服务器触发的upgrade事件提供的request、socket和head三个参数,是正确调用wss.handleUpgrade的关键。
当前问题
我无法访问底层HTTP服务器,也找不到从Express中间件的req、res对象中直接提取这三个参数的方法(包括express-ws这类库也依赖底层HTTP服务器实例)。
目前我已经从Express的req对象中拿到了request和req.socket,但缺少head参数:
wss.handleUpgrade(req, req.socket, ???, (websocket) => { wss.emit('connection', websocket, req); });
尝试的方案及报错
我尝试手动构造head参数,代码如下:
if (path === '/transaction/.websocket') { console.log('Transaction request'); // 校验是否为WebSocket升级请求 if (!req.headers.upgrade || req.headers.upgrade.toLowerCase() !== 'websocket') { return res.status(400).send('Invalid WebSocket upgrade request'); } // 获取Sec-WebSocket-Key请求头 const secWebSocketKey = req.headers['sec-websocket-key']; if (!secWebSocketKey) { return res.status(400).send('Missing Sec-WebSocket-Key header'); } // 计算Sec-WebSocket-Accept值 const secWebSocketAccept = crypto .createHash('sha1') .update(secWebSocketKey + '258EAFA5-E914-47DA-95CA-C5AB0DC85B11=') .digest('base64'); // 构造head缓冲区 const head = Buffer.from( `HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: ${secWebSocketAccept}\r\n\r\n`, ); // 执行WebSocket升级处理 wss.handleUpgrade(req, req.socket, head, (websocket) => { wss.emit('connection', websocket, req); }); }
但运行时服务器抛出错误:Uncaught RangeError: Invalid WebSocket frame: RSV1 must be clear。
内容的提问来源于stack exchange,提问作者Eliav Louski
相关产品推荐
相关产品推荐

