Reputation: 661
I'm switching from JavaScript's
vanilla WebSocket
API to Socket.IO
for real-time data about cryptocurrency
prices. While using the regular WebSocket
I had no problem connecting to Kraken
and getting the data I need. However, when trying to connect with Socket.IO
, I get a CORS
error.
Access to XMLHttpRequest at 'https://ws.kraken.com/socket.io/?EIO=3&transport=polling&t=Mxg8_5_' from origin has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
In in the Chrome dev tools network tab, I'm getting an Invalid request
response from Kraken
. I assume Socket.IO
is trying to send some sort of preflight request when trying to establish a websocket
connection and failing due to Kraken's
CORS
policy for http requests. Is there a way to completely bypass this XMLHttpRequest
attempt and immediately try a websocket
connection, seeing as the regular WebSocket
API has no issues establishing this connection and doesn't seem to send a preflight request? Here are both the vanilla and the Socket.IO
sockets:
// 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);
});
As you can see, these should be functionally very similar, but while the first one works as expected, the second one is throwing the error.
Upvotes: 3
Views: 4723
Reputation: 6745
From the documentation:
What Socket.IO is not
Socket.IO is NOT a WebSocket implementation. Although Socket.IO indeed uses WebSocket as a transport when possible, it adds some metadata to each packet: the packet type, the namespace and the packet id when a message acknowledgement is needed. That is why a WebSocket client will not be able to successfully connect to a Socket.IO server, and a Socket.IO client will not be able to connect to a WebSocket server either. Please see the protocol specification here.
So if the endpoint you're trying to use isn't running a Socket.IO server, this isn't going to work.
That said, if it is, you can force the use of websockets using the transports
parameter:
const ioSocket = io(endpoint, {
transports: ['websocket'] // forces websockets only
});
Bottom Line: Socket.IO is not a replacement for a WebSockets connection. Socket.IO uses WebSockets to accomplish its goal: "Socket.IO is a library that enables real-time, bidirectional and event-based communication between the browser and the server".
Upvotes: 6
Reputation: 2989
You're getting the CORS error because socket.io attempts pure HTTP-based long-polling connection first and that's what fails. You should manually set your client to attempt websocket first:
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);
});
From the socket.io docs:
With websocket transport only
By default, a long-polling connection is established first, then upgraded to “better” transports (like WebSocket). If you like to live dangerously, this part can be skipped:
const socket = io({ transports: ['websocket'] });
// on reconnection, reset the transports option, as the Websocket // connection may have failed (caused by proxy, firewall, browser, ...) socket.on('reconnect_attempt', () => { socket.io.opts.transports = ['polling', 'websocket']; });
Upvotes: 1