Custom parser
Since Socket.IO v2.0.0, it is now possible to provide your own parser, in order to control the marshalling / unmarshalling of packets.
Server
const httpServer = require("http").createServer(); const io = require("socket.io")(httpServer, { parser: myParser }); |
Client
const socket = io({ parser: myParser }); |
Implementing your own parser
Here is a basic example with a parser that uses the JSON.stringify()
and JSON.parse()
methods:
const Emitter = require("component-emitter"); // polyfill of Node.js EventEmitter in the browser class Encoder { /** * Encode a packet into a list of strings/buffers */ encode(packet) { return [JSON.stringify(packet)]; } } class Decoder extends Emitter { /** * Receive a chunk (string or buffer) and optionally emit a "decoded" event with the reconstructed packet */ add(chunk) { const packet = JSON.parse(chunk); if (this.isPacketValid(packet)) { this.emit("decoded", packet); } else { throw new Error("invalid format"); } } isPacketValid({ type, data, nsp, id }) { const isNamespaceValid = typeof nsp === "string"; const isAckIdValid = id === undefined || Number.isInteger(id); if (!isNamespaceValid || !isAckIdValid) { return false; } switch (type) { case 0: // CONNECT return data === undefined || typeof data === "object"; case 1: // DISCONNECT return data === undefined; case 2: // EVENT return Array.isArray(data) && data.length > 0; case 3: // ACK return Array.isArray(data); case 4: // CONNECT_ERROR return typeof data === "object"; default: return false; } } /** * Clean up internal buffers */ destroy() {} } module.exports = { Encoder, Decoder }; |
The default parser
The source code of the default parser (the socket.io-parser
package) can be found here: https://github.com/socketio/socket.io-parser
Example of output:
- basic emit
socket.emit("test", 42); |
will be encoded as:
2["test",42] || |└─ JSON-encoded payload └─ packet type (2 => EVENT) |
- emit with binary, acknowledgement and custom namespace
socket.emit("test", Uint8Array.from([42]), () => { console.log("ack received"); }); |
will be encoded as:
51-/admin,13["test",{"_placeholder":true,"num":0}] |||| || └─ JSON-encoded payload with placeholders for binary attachments |||| |└─ acknowledgement id |||| └─ separator |||└─ namespace (not included when it's the main namespace) ||└─ separator |└─ number of binary attachments └─ packet type (5 => BINARY EVENT) and an additional attachment (the extracted Uint8Array) |
Pros:
- the binary attachments is then base64-encoded, so this parser is compatible with browsers that do not support Arraybuffers, like IE9
Cons:
- packets with binary content are sent as two distinct WebSocket frames (if the WebSocket connection is established)
The msgpack parser
The source code of this parser can be found here: https://github.com/darrachequesne/socket.io-msgpack-parser
Sample usage:
Server
const httpServer = require("http").createServer(); const io = require("socket.io")(httpServer, { parser: require("socket.io-msgpack-parser") }); |
Client (Node.js)
const socket = require("socket.io-client")("https://example.com", { parser: require("socket.io-msgpack-parser") }); |
In the browser, there is now an official bundle which includes this parser:
- https://cdn.socket.io/3.1.1/socket.io.msgpack.min.js
- cdnjs: https://cdnjs.cloudflare.com/ajax/libs/socket.io/3.1.1/socket.io.msgpack.min.js
- jsDelivr: https://cdn.jsdelivr.net/npm/[email protected]/dist/socket.io.msgpack.min.js
- unpkg: https://unpkg.com/[email protected]/dist/socket.io.msgpack.min.js
In that case, you don’t need to specify the parser
option.
Pros:
- packets with binary content are sent as one single WebSocket frame (if the WebSocket connection is established)
- may results in smaller payloads (especially when using a lot of numbers)
Cons:
- incompatible with browsers that do not support Arraybuffers, like IE9
- harder to debug in the Network tab of the browser
© 2014–2021 Automattic
Licensed under the MIT License.
https://socket.io/docs/v3/custom-parser