NextJS,Express,WebSocket 握手期间出错:意外响应代码:200

Posted

技术标签:

【中文标题】NextJS,Express,WebSocket 握手期间出错:意外响应代码:200【英文标题】:NextJS, Express, Error during WebSocket handshake: Unexpected response code: 200 【发布时间】:2019-09-23 00:52:27 【问题描述】:

基本问题可以总结如下:当使用ws在Node中创建Websocket服务器时,服务器选项由快递服务器填充(如this示例),同时使用相同的快递服务器来处理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

谁能在这里为我解释一下?

【问题讨论】:

您与 WS 的实际连接在哪里? IE。 wss.connect.... 嘿。在客户端 index.js 上找到该连接。使用 Websocket Web API 构造函数,详细 here,如:var HOST = location.origin.replace(/^http/, 'ws'); var ws = new WebSocket(HOST); 请注意,正确解析的请求正在到达服务器,它只是未能发出正确的响应。 【参考方案1】:

好的,经过更多的挖掘,我已经解决了这个问题。很简单,我试图向其提供 server = express() 对象的 ws.Server 对象严格来说并不是一个 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);
        )
    );

【讨论】:

以上是关于NextJS,Express,WebSocket 握手期间出错:意外响应代码:200的主要内容,如果未能解决你的问题,请参考以下文章

使用 NextJS + Express 在本地主机上进行 HTTPS

NextJS vs Express [关闭]

Router.push 没有重定向我; Nextjs 与 Express 服务器

在server.js中获取301重定向数据(Express / NextJS)

NextJS 应用程序和 express 服务器之间的内部 API 调用和通信

如何使用 npm 并发包同时运行 Nextjs 应用程序和 Express 服务器?