独立 websocket 服务器的 Socket.io“无效帧头”错误
Posted
技术标签:
【中文标题】独立 websocket 服务器的 Socket.io“无效帧头”错误【英文标题】:Socket.io "Invalid frame header" error with independent websocket server 【发布时间】:2019-04-10 08:59:23 【问题描述】:有没有办法让单独的 websocket 服务器在不同的路径上与 socket.io
一起工作?
let http = require('http');
let express = require('express');
let socketio = require('socket.io');
let websocket = require('ws');
let httpServer = http.createServer();
let expressApp = express();
httpServer.on('request', expressApp);
let socketioserver = socketio(httpServer, path: '/aaaaa/socket.io/' );
socketioServer.of('/').on('connect', () => );
let websocketServer = new websocket.Server( server: httpServer, path: '/aaaaa/graphql' );
httpServer.listen(2233, () => console.log('started'));
我看到的行为是,当创建单独的 websocket 服务器时,socket.io
仍然可以正常运行,但不会升级到 websocket 的连接并失败并出现错误(来自 chrome):
WebSocket connection to 'ws://localhost:2233/aaaaa/socket.io/?EIO=3&transport=websocket&sid=fx4pOT0cegz65JMCAAAB' failed: Invalid frame header
需要明确的是,如果省略了 websocket server 行,socket.io
可以正常工作。
我的具体用例是启用订阅后,apollo-server-express
包会创建一个 websocket 服务器。有没有办法以更友好的方式配置socket.io
?或者,我相信我可以提供一个 websocket 服务器供 apollo 使用,而不是创建一个......我将如何创建它?
用于复制的包版本:
node 8.11.1
express 4.16.4
socket.io 2.1.1
ws 6.1.0
【问题讨论】:
这不是应该完成的。我想让 socket.io 客户端连接到 socket.io 服务器,并且我想要一个 websocket 客户端连接到 websocket 服务器。我不是在寻找交叉沟通。 啊,那我误会了。所以问题是ws
不会将路径/aaaaa/socket.io
上的套接字连接委托给socket.io
?
看起来ws
玩得很好,你必须manually implement the upgrade
event 让你的服务器根据路径委托给websocket服务器或socket.io
实际上,与 /aaaaa/graphql 的 websocket 连接看起来非常好,只是 socket.io 端无法升级
@PatrickRoberts 嘿,成功了!它不像那个链接那样简单明了,但是手动处理升级事件是诀窍。非常感谢!
【参考方案1】:
如果这对其他人有帮助,这是我的派生解决方案:
let [socketioUpgradeListener, apolloUpgradeListener] = httpServer.listeners('upgrade').slice(0);
httpServer.removeAllListeners('upgrade');
httpServer.on('upgrade', (req, socket, head) =>
const pathname = url.parse(req.url).pathname;
if (pathname == '/aaaaa/socket.io/')
socketioUpgradeListener(req, socket, head);
else if (pathname == '/aaaaa/graphql')
apolloUpgradeListener(req, socket, head);
else
socket.destroy();
);
有点烦人,因为这两个库已经完全初始化了他们的 websocket 服务器,并带有大量的事件侦听器,然后我才能搞砸它们。但是,我可以挑选出'upgrade'
侦听器并手动委派它们。当然这并不完美,因为它对初始化顺序和新侦听器很敏感,但对于我的用例来说已经足够了。
如果此解决方案有任何明显的缺陷或与 websocket 服务器委托有任何其他细微差别,请告诉我。
【讨论】:
我不知道你是怎么找到这个解决方案的,但是我在 PeerJS 和 SocketIO 上遇到了同样的问题,后来我搬到 Primus 来发现同样的问题。对于我的 primus 和 peerjs 应用程序的完全相同的问题,您的解决方案就像魅力一样。一定很想知道您是如何找到此解决方案的。 @Sameer Patrick Roberts 在上面的 cmets 中给出的链接让我走上了正确的道路【参考方案2】:同时使用graphql
- 和socket.io-modules
在NestJs
中遇到了同样的问题。作为 Trevor 解决方案的替代方案,您可以将 socket.io
绑定到另一个端口并使用像 nginx 这样的反向代理来解析路径。
app.gateway.ts
@WebSocketGateway(3001)
export class AppGateway implements OnGatewayConnection
handleConnection(
client: any,
payload: any
)
client.emit('Hi from port 3001');
nginx.conf
server
listen 80;
listen [::]:80;
server_name localhost;
location /graphql
proxy_pass http://127.0.0.1:3000;
location /socket.io
proxy_pass http://127.0.0.1:3001/socket.io/;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_http_version 1.1;
当然,您可以跳过最后一部分,直接通过客户端的ws://localhost:3001/socket.io
连接到您的套接字。
【讨论】:
以上是关于独立 websocket 服务器的 Socket.io“无效帧头”错误的主要内容,如果未能解决你的问题,请参考以下文章
Socket Socket.io Websocket HTTP 之间的区别