使用'ws'包从Node.js服务器连接到socket.io服务器

6
我有一个使用流行的ws包来使用WebSockets的Node.js服务器。我想使用此库连接到运行socket.io的第三方服务器。
如果我要在我的服务器上使用socket.io,连接代码将如下所示:
const socket = socketIo('https://api.example.com/1.0/scores')

我尝试使用ws包连接相同的服务,并修改了URL:

const wsClient = new WebSocket('wss://api.example.com/1.0/scores');

但这会导致以下结果:

错误:意外的服务器响应:200

问题: 如何连接到运行socket.io的第三方服务器,从运行ws包的服务器? 附加信息:
  • I've noticed in my searches that some people have suggested appending /socket.io/?EIO=3&transport=websocket to the end of the url. This does not throw the same error as above (> Error: Unexpected server response: 200) nor throw any visible error, but does not appear to work (no data is received from the remote server).
  • Using new WebSocket('ws://api.example.com/1.0/scores?EIO=3&transport=websocket'); to open the connection (via ws) results in the following stack trace:

    { Error: Parse Error
        at Socket.socketOnData 
        at emitOne 
        at Socket.emit 
        // ... 
    }
    

使用NODE_DEBUG=net,https,socket*,ws* node server.js运行您的服务器代码,并在连接发生时发布日志。此问题主要与第三方服务器未正确处理握手有关。 - Tarun Lalwani
@TarunLalwani 日志:https://gist.github.com/Orbyt/12368837372fb7dd3a8f69e3ec0e521b - Orbit
这个问题以前已经被回答过了: https://dev59.com/1lsV5IYBdhLWcg3w6iV8 - bgran
1
尝试仅附加建议的查询(而不修改路径),即如果原始URL为'ws://api.example.com/1.0/scores',则尝试ws://api.example.com/1.0/scores?EIO=3&transport=websocket - bgran
我注意到您在创建WebSocket时使用了wss://,请尝试使用示例中使用的ws://和EIO=3&tarnsport=websocket。 - Jordan H
显示剩余5条评论
2个回答

1
因为Socket.IO不能保证会像您期望的那样托管WebSocket服务器,所以您应该使用它们的标准客户端软件包。
npm i socket.io-client

然后在你的代码中使用这个包:
const ioClient = require('socket.io-client')('https://example.com/1.0/scores')

socket.io-client的完整文档可在其GitHub存储库上获得。

注意:但说实话,如果可能的话,使用WebSockets会更好。WebSockets已经得到浏览器的广泛支持,并且相当标准化。Socket.IO很少是必要的,可能会增加一些开销。


我的服务器已经在使用 ws 包。问题是如何连接到一个已经使用 socket.io 的第三方服务器。我已经编辑了问题以使其更清晰。 - Orbit
@Orbit 好的,我明白你想做什么,但仅使用WebSockets连接并不遵循惯例,而且可能会在未来出现问题。我强烈建议你使用官方的socket.io-client包(就像我的答案中所示)来完成你想要做的事情。 - ethnanon
是的,使用官方的socket.io客户端可以正常工作,但这不是问题所在。 - Orbit

1
socket.io api利用了websockets,但是它还有很多其他功能,例如HTTP握手、会话ID,甚至在需要时可以处理到其他协议的故障转移。
到目前为止,您已经解决了一半的问题。通过添加行socket.io/?EIO=3&transport=websocket,您正在指定socket.io服务器要采取的参数。 EIO=3指定engine.io版本号,socket.io正在使用该版本。在这种情况下,您要求engine.io版本= 3 transport=websocket指定要使用的传输协议。正如我之前所说,socket.io在故障转移等情况下使用其他协议。此部分强制socket.io使用websocket作为首选协议。
现在剩下的是WebSocket。 WebSocket允许扩展,其中包括发送数据时常用的不同类型的压缩。这就是导致您的Parse Error的原因。
请尝试以下操作(在此处找到):
const WebSocket = require('ws');
const ws = new WebSocket('ws://server/socket.io/?EIO=3&transport=websocket', {
   perMessageDeflate: false
});

通过设置perMessageDeflate:false,您正在指定“不压缩数据”。由于这是WebSocket扩展,因此也有不同的变体。如果不起作用,请尝试使用以下内容:
  • x-webkit-deflate-frame
  • perframe-deflate
免责声明:此信息来自我所做的研究。我不是“socket.io专家”,如果有任何错误,请发表评论,我会编辑帖子。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接