Socket.IO 尝试通过 https:// 而不是 wss:// 进行连接,并收到 CORS 错误



我正在从JavaScript's香草WebSocketAPI切换到Socket.IO以获取有关cryptocurrency价格的实时数据。在使用常规WebSocket时,我没有问题连接到Kraken并获取我需要的数据。但是,当尝试连接Socket.IO时,我收到CORS错误。

CORS 策略阻止了从源访问 "https://ws.kraken.com/socket.io/?EIO=3&transport=polling&t=Mxg8_5_" 处的 XMLHttpRequest:请求的资源上不存在"访问控制允许源"标头。

在Chrome开发工具网络选项卡中,我收到了来自KrakenInvalid request回复。我假设Socket.IO在尝试建立websocket连接时尝试发送某种预检请求,但由于 http 请求Kraken'sCORS策略而失败。有没有办法完全绕过这种XMLHttpRequest尝试并立即尝试websocket连接,因为常规WebSocketAPI 在建立此连接时没有问题并且似乎没有发送预检请求?以下是香草和Socket.IO插座:

// vanilla websocket
const vanillaWS = new WebSocket('wss://ws.kraken.com');
vanillaWS.onopen = () => {
console.log('vanilla websocket opened');
}
vanillaWS.onmessage = (message) => {
console.log(message.data);
}
// socket.io websocket
const ioSocket = io('wss://ws.kraken.com');
ioSocket.on('connect', () => {
console.log('socket.io socket opened');
});
ioSocket.on('message', (message) => {
console.log(message.data);
});

如您所见,这些在功能上应该非常相似,但是虽然第一个按预期工作,但第二个正在抛出错误。

从文档中:

Socket.IO 不是

Socket.IO 不是 WebSocket 实现。虽然确实 Socket.IO 尽可能使用 WebSocket 作为传输,它会添加一些元数据到 每个数据包:数据包类型、命名空间和数据包 ID,当 需要消息确认。这就是为什么 WebSocket 客户端将 无法成功连接到 Socket.IO 服务器,并且 Socket.IO 客户端将无法连接到 WebSocket 服务器 要么。请参阅协议规范 这里。

因此,如果您尝试使用的端点未运行 Socket.IO 服务器,则此操作将不起作用。

也就是说,如果是,您可以使用transports参数强制使用 websockets:

const ioSocket = io(endpoint, {
transports: ['websocket']  // forces websockets only
});

底线:Socket.IO 不能替代WebSockets连接。 Socket.IO 使用 WebSockets 来实现其目标:">Socket.IO 是一个库,可以在浏览器和服务器之间实现实时、双向和基于事件的通信"。

您会收到 CORS 错误,因为 socket.io 首先尝试纯基于 HTTP 的长轮询连接,这就是失败的原因。您应该手动将客户端设置为首先尝试 websocket:

var options = {
allowUpgrades: true,
transports: ['websocket', 'polling'],
};
var sock = io(server, options);
sock.on('connect', () => {
console.log('socket.io socket opened');
});
sock.on('message', (message) => {
console.log(message.data);
});

从 socket.io 文档中:

仅使用 websocket 传输

默认情况下,首先建立长轮询连接,然后 升级到"更好"的传输(如 WebSocket(。如果你喜欢生活 危险的是,可以跳过这部分:

const socket = io({ transports: ['websocket'] }(;

重新连接时,重置传输选项,作为 Websocket//连接可能失败(由代理、防火墙、浏览器等引起( socket.on('reconnect_attempt', (( => { socket.io.opts.transports = ["轮询"、"网络套接字"];});

最新更新