Hello everyone!

We have just published a new minor version of Socket.IO: 4.1.0

New features

Add support for inter-server communication

This feature might be useful in a multi-server setup: you can now broadcast events between your Socket.IO servers.

Syntax:

io.serverSideEmit("hello", "world");

And on the receiving side:

io.on("hello", (arg1) => {
console.log(arg1); // prints "world"
});

Acknowledgements are supported too:

// server A
io.serverSideEmit("ping", (err, responses) => {
console.log(responses[0]); // prints "pong"
});

// server B
io.on("ping", (cb) => {
cb("pong");
});

A few notes:

// server A
io.of("/custom").serverSideEmit("sync");

// server B
io.of("/custom").on("sync", () => {
// ...
});
  • the connection, connect and new_namespace (see below) strings are reserved and cannot be used in your application.

  • you can send any number of arguments, but binary structures are currently not supported (the array of arguments will be JSON.stringify-ed)

Example:

io.serverSideEmit("hello", "world", 1, "2", { 3: "4" });

The Redis adapter and its associated emitter have been updated to support this new functionality.

Emit an event when a namespace is created

The new_namespace event will be emitted by the Server instance when a new namespace is created:

io.on("new_namespace", (namespace) => {
// ...
});

This can be useful for example:

  • to attach a shared middleware to each namespace
io.on("new_namespace", (namespace) => {
namespace.use(myMiddleware);
});
io.of(/\/nsp-\w+/);

io.on("new_namespace", (namespace) => {
console.log(namespace.name);
});

Add a way to customize the response headers

The underlying Engine.IO server, which manages the low-level connection (HTTP long-polling and/or WebSocket), will now emit two additional events:

  • initial_headers
  • headers

Like the name suggests, the initial_headers event will be emitted only for the first HTTP request of the session, while the headers event will be emitted for each HTTP request (including the WebSocket upgrade).

Example:

io.engine.on("initial_headers", (headers, req) => {
headers["test"] = "123";
headers["set-cookie"] = "mycookie=456";
});

io.engine.on("headers", (headers, req) => {
headers["test"] = "789";
});

Note: it was previously possible to achieve this by listening to the “request” event, but this should be easier with those new events:

const httpServer = require("http").createServer();
const { Server } = require("socket.io");
const io = new Server(httpServer);

httpServer.prependListener("request", (req, res) => {
res.setHeader("test", "789");
});

Add a way to get access to the reason of a connection error

The underlying Engine.IO server will also emit a new event: connection_error.

Syntax:

io.engine.on("connection_error", (err) => {
console.log(err.req); // the request object
console.log(err.code); // the error code, for example 1
console.log(err.message); // the error message, for example "Session ID unknown"
console.log(err.context); // some additional error context
});

Here is the list of possible error codes:

Code Message
0 “Transport unknown”
1 “Session ID unknown”
2 “Bad handshake method”
3 “Bad request”
4 “Forbidden”
5 “Unsupported protocol version”

Add a way to ignore the beforeunload event

A few months ago, a user reported a weird behavior when reloading a page: on Firefox, the Socket instance would emit a disconnect event, but not on Chrome or Safari.

We have published a fix for this issue in socket.io-client@3.1.1, by silently closing the connection when receiving a beforeunload event from the browser.

Unfortunately, this fix had unintended consequences: if you relied on the beforeunload event to prompt the user for confirmation (“your last modifications are not saved yet, do you really want to leave?”), the Socket.IO connection would now be closed, even if the user decided to stay on the page.

That’s why we have added the closeOnBeforeunload option, to give you total control over this behavior:

const socket = io("/", {
closeOnBeforeunload: false // defaults to true
})
  • closeOnBeforeunload: true (the default value) will make all browsers behave the same (no disconnect event when reloading the page)
  • closeOnBeforeunload: false will ignore the beforeunload event, but you will get a disconnect event on Firefox

That’s all for this release, thanks for reading!

Caught a mistake? Edit this page on GitHub