カスタムパーサー
Socket.IO v2.0.0以降、パケットのマーシャリング/アンマーシャリングを制御するために、独自のパーサーを提供することが可能になりました。
サーバー
import { Server } from "socket.io";
const io = new Server({
parser: myParser
});
クライアント
import { io } from "socket.io-client";
const socket = io({
parser: myParser
});
利用可能なパーサー
デフォルトパーサーの他に、利用可能なパーサーのリストを以下に示します。
パッケージ | 説明 |
---|---|
socket.io-circular-parser | デフォルトのパーサーと似ていますが、循環参照を処理します。 |
socket.io-msgpack-parser | パケットのエンコードにMessagePackを使用します(notepack.io パッケージに基づいています)。 |
@skgdev/socket.io-msgpack-javascript | パケットのエンコードにMessagePackを使用します(@msgpack/msgpack パッケージに基づいています)。 |
socket.io-json-parser | パケットのエンコードにJSON.stringify() とJSON.parse() を使用します。 |
socket.io-cbor-x-parser | パケットのエンコードにcbor-xを使用します。 |
@socket.io/devalue-parser | パケットのエンコードにdevalueを使用します。 |
独自のパーサーの実装
以下は、JSON.stringify()
とJSON.parse()
メソッドを使用するパーサーの基本的な例です。
import { Emitter } from "@socket.io/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)];
}
}
function isObject(value) {
return Object.prototype.toString.call(value) === "[object Object]";
}
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 || isObject(data);
case 1: // DISCONNECT
return data === undefined;
case 2: // EVENT
return Array.isArray(data) && typeof data[0] === "string";
case 3: // ACK
return Array.isArray(data);
case 4: // CONNECT_ERROR
return isObject(data);
default:
return false;
}
}
/**
* Clean up internal buffers
*/
destroy() {}
}
export const parser = { Encoder, Decoder };
デフォルトパーサー
デフォルトパーサー(socket.io-parser
パッケージ)のソースコードは、こちらにあります: https://github.com/socketio/socket.io-parser
出力例
- 基本的なemit
socket.emit("test", 42);
以下のようにエンコードされます
2["test",42]
||
|└─ JSON-encoded payload
└─ packet type (2 => EVENT)
- バイナリ、確認応答、カスタム名前空間を持つemit
socket.emit("test", Uint8Array.from([42]), () => {
console.log("ack received");
});
以下のようにエンコードされます
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)
長所
- バイナリの添付ファイルはbase64でエンコードされるため、このパーサーはIE9のようにArraybufferをサポートしないブラウザと互換性があります。
短所
- バイナリコンテンツを含むパケットは、2つの異なるWebSocketフレームとして送信されます(WebSocket接続が確立されている場合)。
msgpackパーサー
このパーサーは、MessagePackシリアル化形式を使用します。
このパーサーのソースコードは、こちらにあります: https://github.com/socketio/socket.io-msgpack-parser
使用例
サーバー
import { Server } from "socket.io";
import customParser from "socket.io-msgpack-parser";
const io = new Server({
parser: customParser
});
クライアント (Node.js)
import { io } from "socket.io-client";
import customParser from "socket.io-msgpack-parser";
const socket = io("https://example.com", {
parser: customParser
});
ブラウザでは、このパーサーを含む公式バンドルが利用可能です。
- https://cdn.socket.io/4.7.5/socket.io.msgpack.min.js
- cdnjs: https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.7.5/socket.io.msgpack.min.js
- jsDelivr: https://cdn.jsdelivr.net/npm/socket.io-client@4.7.5/dist/socket.io.msgpack.min.js
- unpkg: https://unpkg.com/socket.io-client@4.7.5/dist/socket.io.msgpack.min.js
その場合、parser
オプションを指定する必要はありません。
長所
- バイナリコンテンツを含むパケットは、単一のWebSocketフレームとして送信されます(WebSocket接続が確立されている場合)。
- ペイロードが小さくなる可能性があります(特に多数の数値を使用する場合)。
短所
- IE9のようにArraybufferをサポートしないブラウザと互換性がありません。
- ブラウザのネットワークタブでデバッグするのが難しい。
情報
socket.io-msgpack-parser
は、notepack.io
MessagePack実装に依存しています。この実装は主にパフォーマンスと最小限のバンドルサイズに焦点を当てており、拡張型のような機能はサポートしていません。 公式のJavaScript実装に基づくパーサーについては、このパッケージをご確認ください。