Hello everyone!
We have just published a new minor version of Socket.IO: 4.1.0
New features
- Add support for inter-server communication
- Emit an event when a namespace is created
- Add a way to customize the response headers
- Add a way to get access to the reason of a connection error
- Add a way to ignore the
beforeunload
event
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:
- the events are specific to each namespace
// server A
io.of("/custom").serverSideEmit("sync");
// server B
io.of("/custom").on("sync", () => {
// ...
});
the
connection
,connect
andnew_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);
});
- to track the dynamically created namespaces
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 (nodisconnect
event when reloading the page)closeOnBeforeunload: false
will ignore thebeforeunload
event, but you will get adisconnect
event on Firefox
That's all for this release, thanks for reading!