自定义解析器
从 Socket.IO v2.0.0 开始,现在可以提供自己的解析器,以控制数据包的编组/解组。
服务器
import{Server}from"socket.io";
const io =newServer({
parser: myParser
});
客户端
import{ io }from"socket.io-client";
const socket =io({
parser: myParser
});
Available parsers
Besides the default parser, here is the list of available parsers:
| Package | Description |
|---|---|
socket.io-circular-parser | Similar to the default parser, but handles circular references. |
socket.io-msgpack-parser | Uses MessagePack to encode the packets (based on the notepack.io package). |
@skgdev/socket.io-msgpack-javascript | Uses MessagePack to encode the packets (based on the @msgpack/msgpack package). |
socket.io-json-parser | Uses JSON.stringify() and JSON.parse() to encode the packets. |
socket.io-cbor-x-parser | Uses cbor-x to encode the packets. |
@socket.io/devalue-parser | Uses devalue to encode the packets. |
实现自己的解析器
这是一个使用JSON.stringify()和JSON.parse()方法的解析器的基本示例:
import{Emitter}from"@socket.io/component-emitter";// polyfill of Node.js EventEmitter in the browser
classEncoder{
/**
* Encode a packet into a list of strings/buffers
*/
encode(packet){
return[JSON.stringify(packet)];
}
}
functionisObject(value){
returnObject.prototype.toString.call(value)==="[object Object]";
}
classDecoderextendsEmitter{
/**
* 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{
thrownewError("invalid format");
}
}
isPacketValid({ type, data, nsp, id }){
const isNamespaceValid =typeof nsp ==="string";
const isAckIdValid = id ===undefined||Number.isInteger(id);
if(!isNamespaceValid ||!isAckIdValid){
returnfalse;
}
switch(type){
case0:// CONNECT
return data ===undefined||isObject(data);
case1:// DISCONNECT
return data ===undefined;
case2:// EVENT
returnArray.isArray(data)&&typeof data[0]==="string";
case3:// ACK
returnArray.isArray(data);
case4:// CONNECT_ERROR
returnisObject(data);
default:
returnfalse;
}
}
/**
* Clean up internal buffers
*/
destroy(){}
}
exportconst 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)
- 使用二进制、确认和自定义命名空间发出
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 编码的,所以这个解析器与不支持 Arraybuffers的浏览器兼容,比如 IE9
缺点:
- 具有二进制内容的数据包作为两个不同的 WebSocket 帧发送(如果建立了 WebSocket 连接)
msgpack 解析器
此解析器使用MessagePack序列化格式。
这个解析器的源代码可以在这里找到:https://github.com/socketio/socket.io-msgpack-parser
示例用法:
服务器
import{Server}from"socket.io";
importcustomParserfrom"socket.io-msgpack-parser";
const io =newServer({
parser: customParser
});
客户端 (Node.js)
import{ io }from"socket.io-client";
importcustomParserfrom"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 连接)
- 可能会导致更小的有效载荷(尤其是在使用大量数字时)
缺点:
- 与不支持 Arraybuffers的浏览器不兼容,例如 IE9
- 在浏览器的网络选项卡中更难调试
信息
请注意,这socket.io-msgpack-parser依赖于notepack.ioMessagePack 实现。此实现主要关注性能和最小包大小,因此不支持扩展类型等功能。对于基于官方 JavaScript 实现的解析器,请查看这个包。