在有些情况下,我们在使用 WebSocket 通信的时候,需要对方进行回应,但由于 WebSocket 是全双工交互,所以不能像 http 协议一样,发送之后能够得到对应的回复,为了能够很好的获取到对应的回复,设计了一个简单的协议,各位有需要的话,可以参考看看。
协议的原理很简单,即:记录消息ID。
举个例子🌰
JavaScript 发送数据需要对方进行回复;那么对发送的数据进行封装:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62 sendJson = function (json) {
return new Promise(((resolve, reject) => {
let dataPackage = {
_message_id: json.$_message_id || {web_id: 0, sdk_id: 0},
data: json,
}
dataPackage._message_id.web_id = _message_id++;
if (_message_id > _callback_max_id) {
_message_id = 0;
}
try {
webSocket.send(JSON.stringify(dataPackage));
_callback[dataPackage._message_id.web_id] = {
resolve: resolve, reject: reject
}
} catch (e) {
reject(e);
}
}));
}
webSocket.onmessage = async function (event) {
try {
let dataPackage = JSON.parse(event.data);
let _message_id = dataPackage._message_id;
let json = dataPackage.data;
json.$_message_id = _message_id;
let message;
try {
if (_message_id && _message_id.web_id > 0) {
let func = _callback[_message_id.web_id];
delete _callback[_message_id.web_id];
_message_id.web_id = 0;
json.$_message_id.web_id = 0;
if (json.code >= 0) {
func.resolve(json);
} else {
func.reject(json);
}
} else {
message = option && option.onmessage && await option.onmessage(json);
}
} catch (e) {
message = {
code: -1,
message: typeof e == "string" ? e : JSON.stringify(e),
data: null,
};
} finally {
let dataPackage = {
_message_id: _message_id,
data: message
}
delete message.$_message_id;
if (dataPackage._message_id && dataPackage._message_id.sdk_id) {
self.sendJsonBack(dataPackage);
}
}
} catch (e) {
}
};变量说明:
web_id和sdk_id在这里分别表示网页端消息 id 和sdk(我这边另一头是作为sdk提供,所以命名为sdk_id) 端消息ID。webSocket为WebSocket对象,用于接收和发送WebSocket数据。_callback与_callback_max_id分别为记录回调函数,以及最大回调记录,可以在接收到回复的情况下进行回调,从而与发送关联。onmessage为WebSocket接收数据回调,通过接收的_message_id内web_id和sdk_id(JavaScript端主要是web_id),然后根据webSocket进行对应数据回调。- 为保证对方也能够得到消息的回复,所以在
finally也进行dataPackage._message_id.sdk_id即sdk_id的判定,如果对方发送的数据包含dataPackage._message_id.sdk_id,那么表示这个包为发送包,非回应包,需要JavaScript这端进行回应。
JavaScript 端完整例子:
1 | const _callback_max_id = 1000000000; |