基本问题可以总结如下:当使用ws在Node中创建Websocket服务器时,其中的服务器选项由Express服务器填充(例如this),而使用同一Express服务器处理NextJS的路由(如this示例中所示),升级标头似乎未正确解析。
express不会将请求路由到Websocket服务器,而是发送回HTTP 200 OK响应。
我一直在寻找答案,可能是我根本不了解问题。 NextJS的github上的issue中提出了一个可能相关的问题。他们建议在本地的next.config.js中设置WebsocketPort和WebsocketProxyPort选项,但是我尝试这样做没有任何作用。
有关服务器代码的最小示例可以在下面找到。您可能会找到完整的示例here。
const express = require('express')
const next = require('next')
const SocketServer = require('ws').Server;
const port = parseInt(process.env.PORT, 10) || 3000
const dev = process.env.NODE_ENV !== 'production'
const app = next({ dev })
const handle = app.getRequestHandler()
app.prepare().then(() => {
const server = express()
server.all('*', (req, res) => {
return handle(req, res)
})
server.listen(port, err => {
if (err) throw err
console.log(`> Ready on http://localhost:${port}`)
})
const wss = new SocketServer({ server });
wss.on('connection', function connection(ws, request) {
console.log('Client connected');
ws.on('close', () => console.log('Client disconnected'));
});
wss.on('error', function (error) {
console.log(error);
});
setInterval(() => {
wss.clients.forEach((client) => {
client.send(new Date().toTimeString());
});
}, 1000);
}).catch(ex => {
console.error(ex.stack);
process.exit(1);
});
当然,预期结果是与websocket服务器的连接。相反,我收到以下错误:
WebSocket connection to 'ws://localhost:3000/' failed: Error during WebSocket handshake: Unexpected response code: 200
有人可以在这里为我澄清任何事情吗?
答案 0 :(得分:0)
好吧,经过更多的挖掘,我解决了这个问题。很简单,我试图向其提供ws.Server
对象的server = express()
对象并不是严格意义上的http服务器对象。但是,server.listen()
返回这样的http服务器对象。在这样的对象上,我们可以侦听“升级”调用,然后将其传递给ws.Server
对象的handleUpgrade()
事件侦听器,我们可以通过该事件侦听器进行连接。我将更新我在问题中链接的示例,但相关代码如下:
app.prepare().then(() => {
const server = express()
server.all('*', (req, res) => {
return handle(req, res)
})
const wss = new SocketServer({ server });
wss.on('connection', function connection(ws, request) {
console.log('Client connected');
ws.on('close', () => console.log('Client disconnected'));
});
wss.on('error', function (error) {
console.log(error);
});
let srv = server.listen(port, err => {
if (err) throw err
console.log(`> Ready on http://localhost:${port}`)
})
srv.on('upgrade', function(req, socket, head) {
wss.handleUpgrade(req, socket, head, function connected(ws) {
wss.emit('connection', ws, req);
})
});