spy-client 2.1.2 → 2.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -3
- package/coverage/Chrome 95.0.4638.69 (Mac OS 10.15.7)/html/basicSpec.ts.html +1 -1
- package/coverage/Chrome 95.0.4638.69 (Mac OS 10.15.7)/html/checkSpec.ts.html +1 -1
- package/coverage/Chrome 95.0.4638.69 (Mac OS 10.15.7)/html/headSpec.ts.html +1 -1
- package/coverage/Chrome 95.0.4638.69 (Mac OS 10.15.7)/html/index.html +1 -1
- package/coverage/Chrome 95.0.4638.69 (Mac OS 10.15.7)/html/markSpec.ts.html +1 -1
- package/coverage/Chrome 95.0.4638.69 (Mac OS 10.15.7)/html/metricSpec.ts.html +1 -1
- package/coverage/Chrome 96.0.4664.110 (Mac OS 10.15.7)/html/base.css +224 -0
- package/coverage/Chrome 96.0.4664.110 (Mac OS 10.15.7)/html/basicSpec.ts.html +740 -0
- package/coverage/Chrome 96.0.4664.110 (Mac OS 10.15.7)/html/block-navigation.js +79 -0
- package/coverage/Chrome 96.0.4664.110 (Mac OS 10.15.7)/html/checkSpec.ts.html +479 -0
- package/coverage/Chrome 96.0.4664.110 (Mac OS 10.15.7)/html/favicon.png +0 -0
- package/coverage/Chrome 96.0.4664.110 (Mac OS 10.15.7)/html/headSpec.ts.html +695 -0
- package/coverage/Chrome 96.0.4664.110 (Mac OS 10.15.7)/html/index.html +171 -0
- package/coverage/Chrome 96.0.4664.110 (Mac OS 10.15.7)/html/markSpec.ts.html +284 -0
- package/coverage/Chrome 96.0.4664.110 (Mac OS 10.15.7)/html/metricSpec.ts.html +977 -0
- package/coverage/Chrome 96.0.4664.110 (Mac OS 10.15.7)/html/prettify.css +1 -0
- package/coverage/Chrome 96.0.4664.110 (Mac OS 10.15.7)/html/prettify.js +2 -0
- package/coverage/Chrome 96.0.4664.110 (Mac OS 10.15.7)/html/sort-arrow-sprite.png +0 -0
- package/coverage/Chrome 96.0.4664.110 (Mac OS 10.15.7)/html/sorter.js +170 -0
- package/coverage/Chrome 96.0.4664.55 (Mac OS 10.15.7)/html/base.css +224 -0
- package/coverage/Chrome 96.0.4664.55 (Mac OS 10.15.7)/html/basicSpec.ts.html +740 -0
- package/coverage/Chrome 96.0.4664.55 (Mac OS 10.15.7)/html/block-navigation.js +79 -0
- package/coverage/Chrome 96.0.4664.55 (Mac OS 10.15.7)/html/checkSpec.ts.html +479 -0
- package/coverage/Chrome 96.0.4664.55 (Mac OS 10.15.7)/html/favicon.png +0 -0
- package/coverage/Chrome 96.0.4664.55 (Mac OS 10.15.7)/html/headSpec.ts.html +695 -0
- package/coverage/Chrome 96.0.4664.55 (Mac OS 10.15.7)/html/index.html +171 -0
- package/coverage/Chrome 96.0.4664.55 (Mac OS 10.15.7)/html/markSpec.ts.html +284 -0
- package/coverage/Chrome 96.0.4664.55 (Mac OS 10.15.7)/html/metricSpec.ts.html +977 -0
- package/coverage/Chrome 96.0.4664.55 (Mac OS 10.15.7)/html/prettify.css +1 -0
- package/coverage/Chrome 96.0.4664.55 (Mac OS 10.15.7)/html/prettify.js +2 -0
- package/coverage/Chrome 96.0.4664.55 (Mac OS 10.15.7)/html/sort-arrow-sprite.png +0 -0
- package/coverage/Chrome 96.0.4664.55 (Mac OS 10.15.7)/html/sorter.js +170 -0
- package/dist/head/base.d.ts +12 -7
- package/dist/lib/interface.d.ts +4 -0
- package/dist/spy-client-basic.d.ts +3 -2
- package/dist/spy-client-basic.esm.js +55 -46
- package/dist/spy-client-basic.iife.js +55 -46
- package/dist/spy-client-basic.iife.min.js +1 -1
- package/dist/spy-client-basic.js +55 -46
- package/dist/spy-client-basic.min.js +1 -1
- package/dist/spy-client-basic.mjs +55 -46
- package/dist/spy-client.d.ts +1 -0
- package/dist/spy-client.esm.js +72 -46
- package/dist/spy-client.iife.js +72 -46
- package/dist/spy-client.iife.min.js +1 -1
- package/dist/spy-client.js +72 -46
- package/dist/spy-client.min.js +1 -1
- package/dist/spy-client.mjs +72 -46
- package/dist/spy-head.js +46 -34
- package/dist/spy-head.min.js +1 -1
- package/dist/spy-local-cache.js +28 -41
- package/dist/spy-local-cache.min.js +1 -1
- package/example/index.html +2 -0
- package/example/local-cache.html +77 -15
- package/package.json +3 -3
- package/src/head/base.ts +37 -4
- package/src/head/error.ts +9 -19
- package/src/head/whitescreen.ts +14 -14
- package/src/lib/huffman.ts +37 -56
- package/src/lib/interface.ts +5 -0
- package/src/spy-client-basic.ts +65 -58
- package/src/spy-client.ts +19 -1
- package/src/spy-local-cache.ts +12 -2
package/src/head/error.ts
CHANGED
|
@@ -58,10 +58,10 @@ export function init(conf: SpyHeadConf) {
|
|
|
58
58
|
|
|
59
59
|
// 历史错误
|
|
60
60
|
const historys = [];
|
|
61
|
-
for (let index = 0; index <
|
|
62
|
-
const item =
|
|
63
|
-
const prefix = item.count > 1 ? `(${item.count})` : '';
|
|
64
|
-
historys.push(prefix + (item.msg as string));
|
|
61
|
+
for (let index = 0; index < winerrors.length; index++) {
|
|
62
|
+
const item = winerrors[index];
|
|
63
|
+
const prefix = item.info.count > 1 ? `(${item.info.count})` : '';
|
|
64
|
+
historys.push(prefix + (item.info.msg as string));
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
info.hisErrors = historys.join('----');
|
|
@@ -71,8 +71,8 @@ export function init(conf: SpyHeadConf) {
|
|
|
71
71
|
allow = jsError.handler(obj);
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
-
if (allow !== false
|
|
75
|
-
spyHead.send(obj);
|
|
74
|
+
if (allow !== false) {
|
|
75
|
+
spyHead.send(obj, isSendJserror);
|
|
76
76
|
}
|
|
77
77
|
}
|
|
78
78
|
// 资源错误
|
|
@@ -98,22 +98,12 @@ export function init(conf: SpyHeadConf) {
|
|
|
98
98
|
allow = resourceError.handler(obj);
|
|
99
99
|
}
|
|
100
100
|
|
|
101
|
-
if (allow !== false
|
|
102
|
-
spyHead.send(obj);
|
|
101
|
+
if (allow !== false) {
|
|
102
|
+
spyHead.send(obj, isSendResource);
|
|
103
103
|
}
|
|
104
104
|
|
|
105
105
|
resourceErrorCount++;
|
|
106
106
|
}
|
|
107
|
-
|
|
108
|
-
// 有些错误一下出现很多次,都聚合都一个错误,加上次数
|
|
109
|
-
if (winerrors.length > 0) {
|
|
110
|
-
const lastInfo = winerrors[winerrors.length - 1];
|
|
111
|
-
if (info.msg === lastInfo.msg) {
|
|
112
|
-
lastInfo.count += (lastInfo.count || 0);
|
|
113
|
-
return;
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
winerrors.push(info);
|
|
117
107
|
}
|
|
118
108
|
catch (e) {
|
|
119
109
|
console.error(e);
|
|
@@ -122,7 +112,7 @@ export function init(conf: SpyHeadConf) {
|
|
|
122
112
|
window.addEventListener('error', spyListenError, true);
|
|
123
113
|
spyHead.errorDestroy = function () {
|
|
124
114
|
window.removeEventListener('error', spyListenError, true);
|
|
125
|
-
spyHead.winerrors =
|
|
115
|
+
spyHead.winerrors = [];
|
|
126
116
|
};
|
|
127
117
|
}
|
|
128
118
|
|
package/src/head/whitescreen.ts
CHANGED
|
@@ -42,8 +42,8 @@ export function init(conf: SpyHeadConf) {
|
|
|
42
42
|
const errors = spyHead.winerrors;
|
|
43
43
|
const historys = [];
|
|
44
44
|
for (let i = 0; i < errors.length; i++) {
|
|
45
|
-
const stack = (errors[i].stack || '').split('\n')[0];
|
|
46
|
-
historys.push(`(${i })${stack || errors[i].msg}`);
|
|
45
|
+
const stack = (errors[i].info.stack || '').split('\n')[0];
|
|
46
|
+
historys.push(`(${i })${stack || errors[i].info.msg}`);
|
|
47
47
|
}
|
|
48
48
|
return historys.join(';;');
|
|
49
49
|
}
|
|
@@ -76,19 +76,19 @@ export function init(conf: SpyHeadConf) {
|
|
|
76
76
|
return false;
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
-
if (
|
|
79
|
+
if (selector) {
|
|
80
80
|
setTimeout(function () {
|
|
81
|
-
const obj = {
|
|
82
|
-
group: whiteScreenError.group,
|
|
83
|
-
info: {
|
|
84
|
-
msg: '',
|
|
85
|
-
netTime: getNetTime(),
|
|
86
|
-
hisErrors: getHisError(),
|
|
87
|
-
deviceInfo: getDeviceInfo(),
|
|
88
|
-
},
|
|
89
|
-
} as ErrorHandlerData;
|
|
90
|
-
|
|
91
81
|
if (isWhiteScreen()) {
|
|
82
|
+
const obj = {
|
|
83
|
+
group: whiteScreenError.group,
|
|
84
|
+
info: {
|
|
85
|
+
msg: '',
|
|
86
|
+
netTime: getNetTime(),
|
|
87
|
+
hisErrors: getHisError(),
|
|
88
|
+
deviceInfo: getDeviceInfo(),
|
|
89
|
+
},
|
|
90
|
+
} as ErrorHandlerData;
|
|
91
|
+
|
|
92
92
|
obj.info.msg = 'WhiteScren Error';
|
|
93
93
|
|
|
94
94
|
let allow: boolean | undefined | void = true;
|
|
@@ -97,7 +97,7 @@ export function init(conf: SpyHeadConf) {
|
|
|
97
97
|
}
|
|
98
98
|
|
|
99
99
|
if (allow !== false && obj.info.msg) {
|
|
100
|
-
spyHead && spyHead.send(obj);
|
|
100
|
+
spyHead && spyHead.send(obj, isSend);
|
|
101
101
|
}
|
|
102
102
|
}
|
|
103
103
|
}, timeout);
|
package/src/lib/huffman.ts
CHANGED
|
@@ -46,16 +46,17 @@ class HuffmanNode {
|
|
|
46
46
|
* @param {接受字符数组} bytes
|
|
47
47
|
* @return 返回的就是list形式
|
|
48
48
|
*/
|
|
49
|
-
function getNodes(bytes:
|
|
50
|
-
|
|
49
|
+
function getNodes(bytes: any[]): HuffmanNode[] {
|
|
50
|
+
// 创建一个list
|
|
51
51
|
let list: HuffmanNode[] = [];
|
|
52
|
-
//counts 统计每一个byte出现的次数
|
|
52
|
+
// counts 统计每一个byte出现的次数
|
|
53
53
|
let counts: any = {};
|
|
54
54
|
for (let b of bytes) {
|
|
55
55
|
let count = counts[b]; // map还没有这个字符数据
|
|
56
56
|
if (count == null) {
|
|
57
57
|
counts[b] = 1;
|
|
58
|
-
}
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
59
60
|
counts[b]++;
|
|
60
61
|
}
|
|
61
62
|
}
|
|
@@ -84,7 +85,7 @@ function createHuffmanTree(nodes: HuffmanNode[]): HuffmanNode | undefined {
|
|
|
84
85
|
parent.left = leftNode;
|
|
85
86
|
parent.right = rightNode;
|
|
86
87
|
|
|
87
|
-
|
|
88
|
+
// 将新的二叉树,加入到nodes
|
|
88
89
|
nodes.unshift(parent);
|
|
89
90
|
}
|
|
90
91
|
|
|
@@ -118,44 +119,45 @@ function getHuffmanCodes(root: any) {
|
|
|
118
119
|
string2.push(code);
|
|
119
120
|
if (node != null) { // 如果node == null不处理
|
|
120
121
|
// 判断当前node是叶子节点还是非叶子节点
|
|
121
|
-
if (node.data == null) {
|
|
122
|
+
if (node.data == null) { // 非叶子节点
|
|
122
123
|
// 递归处理
|
|
123
124
|
// 向左递归
|
|
124
125
|
getCodes(node.left, '0', string2);
|
|
125
126
|
// 向右递归
|
|
126
|
-
getCodes(node.right, '1', string2)
|
|
127
|
-
}
|
|
127
|
+
getCodes(node.right, '1', string2);
|
|
128
|
+
}
|
|
129
|
+
else { // 说明是一个叶子节点
|
|
128
130
|
// 就表示找到了某个叶子节点的最后
|
|
129
131
|
huffmanCodes[node.data] = string2.join('');
|
|
130
132
|
}
|
|
131
133
|
}
|
|
132
134
|
}
|
|
133
|
-
getCodes(root,
|
|
135
|
+
getCodes(root, '', strings);
|
|
134
136
|
return huffmanCodes;
|
|
135
137
|
}
|
|
136
138
|
|
|
137
|
-
|
|
139
|
+
|
|
138
140
|
/**
|
|
139
|
-
*
|
|
141
|
+
* 编写一个方法,将字符串对应的bytes数组,通过生成的赫夫曼编码表,返回一个赫夫曼编码压缩后的byte数组
|
|
140
142
|
* @param {原始的字符串对应的bytes数组} bytes
|
|
141
143
|
* @param {生成的赫夫曼编码表} huffmanCodes
|
|
142
144
|
* @return 返回的是字符串对应的一个byte数组
|
|
143
145
|
*/
|
|
144
|
-
function zip(bytes:
|
|
145
|
-
//1.利用huffmanCodes将bytes转成赫夫曼编码对应的字符串
|
|
146
|
+
function zip(bytes: number[], huffmanCodes: any) {
|
|
147
|
+
// 1.利用huffmanCodes将bytes转成赫夫曼编码对应的字符串
|
|
146
148
|
let string = [];
|
|
147
|
-
|
|
149
|
+
// 遍历数组
|
|
148
150
|
for (let b of bytes) {
|
|
149
151
|
string.push(huffmanCodes[b]);
|
|
150
152
|
}
|
|
151
153
|
return string;
|
|
152
154
|
}
|
|
153
155
|
|
|
154
|
-
function huffStringToByte(strs:
|
|
155
|
-
|
|
156
|
+
function huffStringToByte(strs: string[]) {
|
|
157
|
+
// 计算赫夫曼编码字符串的长度
|
|
156
158
|
let str = strs.join('');
|
|
157
159
|
let len = Math.ceil(str.length / 8);
|
|
158
|
-
|
|
160
|
+
// 创建存储压缩后的byte数组
|
|
159
161
|
let huffmanCodeByte = new Array(len + 1);
|
|
160
162
|
let index = 0;
|
|
161
163
|
let strByte: string = ''; // 记录是第几个byte
|
|
@@ -178,7 +180,7 @@ function huffStringToByte(strs: Array<string>) {
|
|
|
178
180
|
* @returns 是经过赫夫曼编码处理后,压缩后的字节数组
|
|
179
181
|
*
|
|
180
182
|
*/
|
|
181
|
-
function huffmanZip(bytes:
|
|
183
|
+
function huffmanZip(bytes: any[]) {
|
|
182
184
|
// 1.生成节点数组
|
|
183
185
|
let nodes = getNodes(bytes);
|
|
184
186
|
// 2.根据节点数组创建赫夫曼树
|
|
@@ -204,31 +206,30 @@ function huffmanZip(bytes: Array<any>) {
|
|
|
204
206
|
* @returns 是byte对应的二进制字符串
|
|
205
207
|
*/
|
|
206
208
|
function huffByteToString(flag: boolean, byte: number) {
|
|
207
|
-
|
|
209
|
+
// 如果是
|
|
208
210
|
if (flag) {
|
|
209
211
|
byte |= 256;
|
|
210
212
|
}
|
|
211
|
-
let str = Number(byte).toString(2)
|
|
213
|
+
let str = Number(byte).toString(2);
|
|
212
214
|
if (flag) {
|
|
213
215
|
return str.substring(str.length - 8);
|
|
214
|
-
} else {
|
|
215
|
-
return str;
|
|
216
216
|
}
|
|
217
|
+
return str;
|
|
217
218
|
}
|
|
218
219
|
|
|
219
|
-
|
|
220
|
+
|
|
220
221
|
/**
|
|
221
|
-
*
|
|
222
|
+
* 编写一份方法,完成对压缩数据的解码
|
|
222
223
|
* @param {赫夫曼编码表} huffmanCodes
|
|
223
224
|
* @param {赫夫曼编码得到的二进制数组} huffmanBytes
|
|
224
225
|
*/
|
|
225
|
-
function decode(huffmanCodes: {[key:string]: string}, huffmanBytes:
|
|
226
|
+
function decode(huffmanCodes: {[key: string]: string}, huffmanBytes: number[]) {
|
|
226
227
|
// 1.先得到二进制字符串 形式11001111111011......
|
|
227
228
|
let heffmanStrArr = [];
|
|
228
229
|
for (let i = 0; i < huffmanBytes.length - 1; i++) {
|
|
229
|
-
|
|
230
|
+
// 判断是不是最后一个字节
|
|
230
231
|
let flag = (i !== huffmanBytes.length - 2);
|
|
231
|
-
heffmanStrArr.push(huffByteToString(flag, huffmanBytes[i]))
|
|
232
|
+
heffmanStrArr.push(huffByteToString(flag, huffmanBytes[i]));
|
|
232
233
|
}
|
|
233
234
|
// 最后一位记录的是最后一位二进制字符串的长度,该长度主要用于补足最后一位丢失的0,所以要单独处理,
|
|
234
235
|
let lastByteStr = heffmanStrArr[heffmanStrArr.length - 1];
|
|
@@ -237,7 +238,7 @@ function decode(huffmanCodes: {[key:string]: string}, huffmanBytes: Array<number
|
|
|
237
238
|
heffmanStrArr[heffmanStrArr.length - 1] = lastByteStr;
|
|
238
239
|
|
|
239
240
|
// 把赫夫曼编码表进行调换
|
|
240
|
-
let map: {[key:string]: string} = {};
|
|
241
|
+
let map: {[key: string]: string} = {};
|
|
241
242
|
for (const [key, value] of Object.entries(huffmanCodes)) {
|
|
242
243
|
map[value] = key;
|
|
243
244
|
}
|
|
@@ -256,14 +257,15 @@ function decode(huffmanCodes: {[key:string]: string}, huffmanBytes: Array<number
|
|
|
256
257
|
break;
|
|
257
258
|
}
|
|
258
259
|
b = map[key];
|
|
259
|
-
if (!b) {
|
|
260
|
+
if (!b) { // 没有匹配到
|
|
260
261
|
count++;
|
|
261
|
-
}
|
|
262
|
-
|
|
262
|
+
}
|
|
263
|
+
else {
|
|
264
|
+
// 匹配到
|
|
263
265
|
flag = false;
|
|
264
266
|
}
|
|
265
267
|
}
|
|
266
|
-
list.push(parseInt(b as string));
|
|
268
|
+
list.push(parseInt(b as string, 10));
|
|
267
269
|
i += count;
|
|
268
270
|
}
|
|
269
271
|
// 当for循环结束后,list中就存放了所有的字符
|
|
@@ -273,7 +275,7 @@ function decode(huffmanCodes: {[key:string]: string}, huffmanBytes: Array<number
|
|
|
273
275
|
|
|
274
276
|
|
|
275
277
|
// js byte[] 和string 相互转换 UTF-8
|
|
276
|
-
function stringToByte(str: string):
|
|
278
|
+
function stringToByte(str: string): number[] {
|
|
277
279
|
let bytes = [];
|
|
278
280
|
for (let index = 0; index < str.length; index++) {
|
|
279
281
|
bytes.push(str.charCodeAt(index));
|
|
@@ -281,7 +283,7 @@ function stringToByte(str: string): Array<number> {
|
|
|
281
283
|
return bytes;
|
|
282
284
|
}
|
|
283
285
|
|
|
284
|
-
function byteToString(arr:
|
|
286
|
+
function byteToString(arr: number[]): string {
|
|
285
287
|
let data = '';
|
|
286
288
|
for (const code of arr) {
|
|
287
289
|
data += String.fromCharCode(code);
|
|
@@ -294,7 +296,7 @@ export function huffmanEncode(str: string) {
|
|
|
294
296
|
let {result, codes} = huffmanZip(bytes);
|
|
295
297
|
return {
|
|
296
298
|
codes,
|
|
297
|
-
result: byteToString(result)
|
|
299
|
+
result: byteToString(result),
|
|
298
300
|
};
|
|
299
301
|
}
|
|
300
302
|
|
|
@@ -303,24 +305,3 @@ export function huffmanDecode(codes: any, str: string) {
|
|
|
303
305
|
const data = decode(codes, bytes);
|
|
304
306
|
return byteToString(data);
|
|
305
307
|
}
|
|
306
|
-
|
|
307
|
-
// For test
|
|
308
|
-
// let content = JSON.stringify({
|
|
309
|
-
// type: 3,
|
|
310
|
-
// fm: 'disp',
|
|
311
|
-
// data: [{"base":{"size":{"doc":{"w":360,"h":4875},"wind":{"w":360,"h":640},"scr":{"w":360,"h":640}},"vsb":"visible","num":16},"t":1629773746698,"path":"/s"}],
|
|
312
|
-
// qid: 10991431029479106376,
|
|
313
|
-
// did: '8dd09c47c7bc90c9fd7274f0ad2c581e',
|
|
314
|
-
// q: '刘德华',
|
|
315
|
-
// t: 1629773746698
|
|
316
|
-
// });
|
|
317
|
-
|
|
318
|
-
// console.log('压缩前的字符串', content, '其长度:', content.length);
|
|
319
|
-
|
|
320
|
-
// const res = huffmanEncode(content);
|
|
321
|
-
// console.log('压缩后的字符串长度', res.result.length);
|
|
322
|
-
// console.log('压缩后的字符串', res.result);
|
|
323
|
-
|
|
324
|
-
// const out = huffmanDecode(res.codes, res.result);
|
|
325
|
-
// console.log('解压后的字符串', out, '其长度:', out.length);
|
|
326
|
-
// console.log('解压后的数据', JSON.stringify(JSON.parse(out)));
|
package/src/lib/interface.ts
CHANGED
package/src/spy-client-basic.ts
CHANGED
|
@@ -68,8 +68,8 @@ interface ErrorOption {
|
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
const defaultLogServer = 'https://sp1.baidu.com/5b1ZeDe5KgQFm2e88IuM_a/mwb2.gif?';
|
|
71
|
-
|
|
72
|
-
const ver = navigator.userAgent.toLowerCase().match(/cpu iphone os (.*?)_/);
|
|
71
|
+
// 基础版本兼容非浏览器环境
|
|
72
|
+
const ver = navigator && navigator.userAgent ? navigator.userAgent.toLowerCase().match(/cpu iphone os (.*?)_/) : '';
|
|
73
73
|
const isLtIos14 = ver && ver[2] && (+ver[2] < 14);
|
|
74
74
|
|
|
75
75
|
|
|
@@ -119,47 +119,28 @@ export default class SpyClient {
|
|
|
119
119
|
lid: option.lid,
|
|
120
120
|
check: option.check !== false,
|
|
121
121
|
sample: option.sample,
|
|
122
|
+
localCache: option.localCache,
|
|
122
123
|
logServer: option.logServer || defaultLogServer,
|
|
123
124
|
};
|
|
124
125
|
}
|
|
125
126
|
|
|
126
|
-
|
|
127
|
-
if (!
|
|
127
|
+
handle(logItem: any) {
|
|
128
|
+
if (!this.check(logItem)) {
|
|
128
129
|
return;
|
|
129
130
|
}
|
|
130
|
-
fetch(url, {
|
|
131
|
-
method: 'POST',
|
|
132
|
-
credentials: 'include',
|
|
133
|
-
headers: {
|
|
134
|
-
'Content-Type': 'application/json'
|
|
135
|
-
},
|
|
136
|
-
body: JSON.stringify(data)
|
|
137
|
-
});
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
sendPost(data: any) {
|
|
141
|
-
let logItems: any[] = isArray(data) ? data : [data];
|
|
142
|
-
const first = logItems[0];
|
|
143
|
-
// 需要在页面暴漏出来pid等基本信息,方式调试查看基本信息与兼容目前的监控
|
|
144
|
-
const query = {
|
|
145
|
-
pid: first.pid,
|
|
146
|
-
type: first.type,
|
|
147
|
-
group: first.group,
|
|
148
|
-
};
|
|
149
|
-
const url = this.option.logServer + stringify(query);
|
|
150
131
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
132
|
+
logItem = assign(
|
|
133
|
+
{
|
|
134
|
+
pid: this.option.pid,
|
|
135
|
+
lid: this.option.lid,
|
|
136
|
+
ts: Date.now(),
|
|
137
|
+
group: 'common',
|
|
138
|
+
},
|
|
139
|
+
logItem
|
|
140
|
+
);
|
|
159
141
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
return;
|
|
142
|
+
if (this.option.localCache) {
|
|
143
|
+
this.option.localCache.addLog(logItem);
|
|
163
144
|
}
|
|
164
145
|
|
|
165
146
|
// 当前api设置了抽样,
|
|
@@ -172,16 +153,6 @@ export default class SpyClient {
|
|
|
172
153
|
return;
|
|
173
154
|
}
|
|
174
155
|
|
|
175
|
-
logItem = assign(
|
|
176
|
-
{
|
|
177
|
-
pid: this.option.pid,
|
|
178
|
-
lid: this.option.lid,
|
|
179
|
-
ts: Date.now(),
|
|
180
|
-
group: 'common',
|
|
181
|
-
},
|
|
182
|
-
logItem
|
|
183
|
-
);
|
|
184
|
-
|
|
185
156
|
delete logItem.sample;
|
|
186
157
|
return logItem;
|
|
187
158
|
}
|
|
@@ -204,19 +175,7 @@ export default class SpyClient {
|
|
|
204
175
|
}
|
|
205
176
|
|
|
206
177
|
const url = this.option.logServer + stringify(logItem);
|
|
207
|
-
|
|
208
|
-
// 目前服务器端支持sendBeacon的post请求,可以优先采用,该api可以降低打点丢失率
|
|
209
|
-
// 但是ios有些问题:在webkit浏览内核环境下,beacon requests的请求方式存在证书验证的bug,发送失败但返回正确.
|
|
210
|
-
// 修复说明在如下链接中:https://bugs.webkit.org/show_bug.cgi?id=193508
|
|
211
|
-
// 但是目前为止,在iOS12.2版本中该问题依旧存在
|
|
212
|
-
// 2021-11-11: 发现ios 14可以送,故小于14的不发送
|
|
213
|
-
if (!(
|
|
214
|
-
!isLtIos14
|
|
215
|
-
&& navigator.sendBeacon
|
|
216
|
-
&& navigator.sendBeacon(url)
|
|
217
|
-
)) {
|
|
218
|
-
(new Image()).src = url;
|
|
219
|
-
}
|
|
178
|
+
this.request(url);
|
|
220
179
|
}
|
|
221
180
|
if (post) {
|
|
222
181
|
this.sendPost(postData);
|
|
@@ -379,4 +338,52 @@ export default class SpyClient {
|
|
|
379
338
|
clearAllMark() {
|
|
380
339
|
this.markCache = {};
|
|
381
340
|
}
|
|
341
|
+
|
|
342
|
+
// send(data, true) 也能以post发送,但是会有严格校验
|
|
343
|
+
// sendPost能以post发送,但没有校验
|
|
344
|
+
sendPost(data: any) {
|
|
345
|
+
let logItems: any[] = isArray(data) ? data : [data];
|
|
346
|
+
const first = logItems[0];
|
|
347
|
+
// 需要在页面暴漏出来pid等基本信息,方式调试查看基本信息与兼容目前的监控
|
|
348
|
+
const query = {
|
|
349
|
+
pid: first.pid,
|
|
350
|
+
type: first.type,
|
|
351
|
+
group: first.group,
|
|
352
|
+
};
|
|
353
|
+
const url = this.option.logServer + stringify(query);
|
|
354
|
+
|
|
355
|
+
this.request(url, data);
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
// 有data时,意味着要用post发送请求
|
|
359
|
+
protected request(url: string, data?: any) {
|
|
360
|
+
if (!(
|
|
361
|
+
!isLtIos14
|
|
362
|
+
&& navigator
|
|
363
|
+
&& navigator.sendBeacon
|
|
364
|
+
&& navigator.sendBeacon(url, data ? JSON.stringify(data) : undefined)
|
|
365
|
+
)) {
|
|
366
|
+
if (data) {
|
|
367
|
+
this.fetch(url, data);
|
|
368
|
+
}
|
|
369
|
+
else {
|
|
370
|
+
(new Image()).src = url;
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
protected fetch(url: string, data: any) {
|
|
376
|
+
if (!fetch) {
|
|
377
|
+
err('Global fetch method doesn\'t exist');
|
|
378
|
+
return;
|
|
379
|
+
}
|
|
380
|
+
fetch(url, {
|
|
381
|
+
method: 'POST',
|
|
382
|
+
credentials: 'include',
|
|
383
|
+
headers: {
|
|
384
|
+
'Content-Type': 'application/json',
|
|
385
|
+
},
|
|
386
|
+
body: JSON.stringify(data),
|
|
387
|
+
});
|
|
388
|
+
}
|
|
382
389
|
}
|
package/src/spy-client.ts
CHANGED
|
@@ -27,7 +27,7 @@ import {
|
|
|
27
27
|
ResOption,
|
|
28
28
|
BigImgOption,
|
|
29
29
|
HttpResOption,
|
|
30
|
-
SlowOption
|
|
30
|
+
SlowOption,
|
|
31
31
|
} from './lib/interface';
|
|
32
32
|
|
|
33
33
|
import FID from './module/fid';
|
|
@@ -70,6 +70,24 @@ export default class SpyClient extends SpyClientBasic {
|
|
|
70
70
|
document.addEventListener('visibilitychange', this.visibilitychangeCB);
|
|
71
71
|
window.addEventListener('beforeunload', this.leave, false);
|
|
72
72
|
window.addEventListener('unload', this.leave, false);
|
|
73
|
+
|
|
74
|
+
this.handleHead();
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
handleHead() {
|
|
78
|
+
if (this.option.localCache) {
|
|
79
|
+
const spyHead = window.__spyHead;
|
|
80
|
+
if (spyHead && spyHead.winerrors) {
|
|
81
|
+
for (let index = 0; index < spyHead.winerrors.length; index++) {
|
|
82
|
+
const obj = spyHead.winerrors[index];
|
|
83
|
+
this.option.localCache.addLog(obj);
|
|
84
|
+
}
|
|
85
|
+
// Head发送的异常,也保存一份到本地,主要是JS错误和资源加载异常
|
|
86
|
+
spyHead.interceptor = (obj: any) => {
|
|
87
|
+
this.option.localCache.addLog(obj);
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
}
|
|
73
91
|
}
|
|
74
92
|
|
|
75
93
|
listenFID(cb: FIDCB) {
|
package/src/spy-local-cache.ts
CHANGED
|
@@ -6,8 +6,9 @@ interface Option {
|
|
|
6
6
|
key: string;
|
|
7
7
|
maxRecordLen: number;
|
|
8
8
|
interval: number;
|
|
9
|
-
onFlush
|
|
10
|
-
onSave
|
|
9
|
+
onFlush?: (res: any) => void;
|
|
10
|
+
onSave?: (res: any) => void;
|
|
11
|
+
onAdd?: (res: any) => boolean;
|
|
11
12
|
storage: 'indexedDB' | 'localstorage' | 'empty';
|
|
12
13
|
}
|
|
13
14
|
|
|
@@ -281,6 +282,9 @@ export default class SpyLocalCache {
|
|
|
281
282
|
maxRecordLen: 30,
|
|
282
283
|
onFlush: () => {},
|
|
283
284
|
onSave: () => {},
|
|
285
|
+
onAdd: () => {
|
|
286
|
+
return true;
|
|
287
|
+
},
|
|
284
288
|
storage: IndexedDB.isSupport()
|
|
285
289
|
? 'indexedDB'
|
|
286
290
|
: LS.isSupport()
|
|
@@ -319,6 +323,12 @@ export default class SpyLocalCache {
|
|
|
319
323
|
}
|
|
320
324
|
|
|
321
325
|
addLog(info: any) {
|
|
326
|
+
if (this.option.onAdd) {
|
|
327
|
+
if (!this.option.onAdd(info)) {
|
|
328
|
+
return;
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
322
332
|
info = JSON.stringify(info);
|
|
323
333
|
|
|
324
334
|
this.tmpList.push(info as string);
|