NextJS、Express、WebSocket 握手期间出错:意外的响应代码:200
NextJS, Express, Error during WebSocket handshake: Unexpected response code: 200
基本问题可以归纳如下:当使用 ws with the server option populated by an express server(as in this example), while using that same express server to handle the routing for NextJS (as in this 示例在 Node 中创建 Websocket 服务器时,升级 header 似乎没有被正确解析。
不是将请求路由到 Websocket 服务器,而是 express 发回 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
谁能帮我解释一下吗?
好的,经过更多挖掘我已经解决了问题。很简单,我试图向其提供 server = express()
对象的 ws.Server
对象严格来说并不是一个 http 服务器对象。但是,server.listen()
returns这样的http服务器对象。在这样的对象上,我们可以监听一个 'upgrade' 调用,我们可以将其传递给我们的 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);
})
});
基本问题可以归纳如下:当使用 ws with the server option populated by an express server(as in this example), while using that same express server to handle the routing for NextJS (as in this 示例在 Node 中创建 Websocket 服务器时,升级 header 似乎没有被正确解析。
不是将请求路由到 Websocket 服务器,而是 express 发回 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
谁能帮我解释一下吗?
好的,经过更多挖掘我已经解决了问题。很简单,我试图向其提供 server = express()
对象的 ws.Server
对象严格来说并不是一个 http 服务器对象。但是,server.listen()
returns这样的http服务器对象。在这样的对象上,我们可以监听一个 'upgrade' 调用,我们可以将其传递给我们的 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);
})
});