解决TextEncoder和TextDecoder在IE下不兼容的问题
# 背景国产加密sm4兼容IE处理
直接修改源码,不做引用处理;
对于只是utf-8编码,我们可以使用浏览器兼容的unescape
和encodeURIComponent
配合,进行模拟:
var encoder = new TextEncoder();
encoder.encode("中文abc");
//result : Uint8Array(9) [228, 184, 173, 230, 150, 135, 97, 98, 99]
unescape(encodeURIComponent("中文abc")).split("").map(val => val.charCodeAt());
//result : (9) [228, 184, 173, 230, 150, 135, 97, 98, 99]
1
2
3
4
5
2
3
4
5
同样的,解码如下:
var decoder = new TextDecoder();
decoder.decode(Uint8Array.from([228, 184, 173, 230, 150, 135, 97, 98, 99]));
//result : 中文abc
decodeURIComponent(escape(String.fromCharCode(...[228, 184, 173, 230, 150, 135, 97, 98, 99])));
//result : 中文abc
1
2
3
4
5
2
3
4
5
为了兼容IE ,以ES5封装如下:
/**
* @description 这是一个补丁包。用来解决新引入的stomp中引用textEncoder和textDecoder在IE下不兼容的问题
* 由于stomp源码中只使用了最基本的utf8编码,故可以用支持ie的 unescape 和 encodeURIComponent伪装该函数
*/
(function(window) {
if(typeof TextEncoder=="function") {return;}
function _TextEncoder() {
//--DO NOTHING
}
_TextEncoder.prototype.encode = function(s) {
//return unescape(encodeURIComponent(s)).split('').map(function(val) {return val.charCodeAt();});
var data=unescape(encodeURIComponent(s)).split('').map(function(val) {return val.charCodeAt();});
return typeof Uint8Array=="function"?new Uint8Array(data):data;//new TextEncoder().encode返回Uint8Array
};
function _TextDecoder() {
//--DO NOTHING
}
_TextDecoder.prototype.decode = function(code_arr) {
return decodeURIComponent(escape(String.fromCharCode.apply(null, code_arr)));
};
window.TextEncoder = _TextEncoder;
window.TextDecoder = _TextDecoder;
})(this);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
加密封装:
const base64js = require('base64-js');
var utf8Encodings = ['utf8', 'utf-8', 'unicode-1-1-utf-8'];
function MyTextEncoder(encoding) {
if (utf8Encodings.indexOf(encoding) < 0 && typeof encoding !== 'undefined' && encoding != null) {
throw new RangeError('Invalid encoding type. Only utf-8 is supported');
} else {
this.encoding = 'utf-8';
this.encode = function(str) {
if (typeof str !== 'string') {
throw new TypeError('passed argument must be of tye string');
}
var binstr = unescape(encodeURIComponent(str)),
arr = new Uint8Array(binstr.length);
const split = binstr.split('');
for (let i = 0; i < split.length; i++) {
arr[i] = split[i].charCodeAt(0);
}
return arr;
};
}
}
function MyTextDecoder(encoding) {
if (utf8Encodings.indexOf(encoding) < 0 && typeof encoding !== 'undefined' && encoding != null) {
throw new RangeError('Invalid encoding type. Only utf-8 is supported');
} else {
this.encoding = 'utf-8';
this.decode = function(view, options) {
if (typeof view === 'undefined') {
return '';
}
var stream = typeof options !== 'undefined' && stream in options ? options.stream : false;
if (typeof stream !== 'boolean') {
throw new TypeError('stream option must be boolean');
}
if (!ArrayBuffer.isView(view)) {
throw new TypeError('passed argument must be an array buffer view');
} else {
var arr = new Uint8Array(view.buffer, view.byteOffset, view.byteLength),
charArr = new Array(arr.length);
for (let i = 0; i < arr.length; i++) {
charArr[i] = String.fromCharCode(arr[i]);
}
return decodeURIComponent(escape(charArr.join('')));
}
};
}
}
class Crypt {
/**
* Converts a JS string to an UTF-8 uint8array.
*
* @static
* @param {String} str 16-bit unicode string.
* @return {Uint8Array} UTF-8 Uint8Array.
* @memberof Crypt
*/
static stringToArrayBufferInUtf8(str) {
// if not browser env, then require node.js's util. otherwise just use window's
// const TextEncoder =
// typeof window === 'undefined' ? require('util').TextEncoder : window.TextEncoder;
// always utf-8
const TextEncoder = window.TextEncoder ? window.TextEncoder : MyTextEncoder;
let encoder = new TextEncoder();
console.log(encoder);
return encoder.encode(str);
}
/**
* Converts an UTF-8 uint8array to a JS string.
*
* @static
* @param {Uint8Array} strBuffer UTF-8 Uint8Array.
* @return {String} 16-bit unicode string.
* @memberof Crypt
*/
static utf8ArrayBufferToString(strBuffer) {
// if not browser env, then require node.js's util. otherwise just use window's
// const TextDecoder =
// typeof window === 'undefined' ? require('util').TextDecoder : window.TextDecoder;
const TextDecoder = window.TextDecoder ? window.TextDecoder : MyTextDecoder;
let decoder = new TextDecoder('utf-8');
return decoder.decode(strBuffer);
}
/**
* crypt a utf8 byteArray to base64 string
*
* @static
* @param {Uint8Array} strBuffer UTF-8 Uint8Array.
* @returns {String} base64 str
* @memberof Crypt
*/
static arrayBufferToBase64(strBuffer) {
return base64js.fromByteArray(strBuffer);
}
/**
* crypt base64 stringa to utf8 byteArray
*
* @static
* @param {String} base64 str
* @returns {Uint8Array} strBuffer UTF-8 Uint8Array.
* @memberof Crypt
*/
static base64ToArrayBuffer(base64) {
return base64js.toByteArray(base64);
}
}
export default Crypt;
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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
上次更新: 2022/04/15, 05:41:29