关于人机交互过程中http通讯及浏览器中的HTML编码、URL编码、base64编码及转义
目录
关于人机交互过程中http通讯及浏览器中的HTML编码、URL编码、base64编码及转义
1、html编码的特殊字符
HTML encoding character
HTML 和 XHTML 用标准的 7 比特 ASCII 代码在网络上传输数据。
1.1、HTML 实体
HTML语言 中的“保留字”,即某些预留字符。
比如:不能在除“元素”意外的位置,使用小于号(<)和大于号(>),浏览器会误解为它们是标签。
若有需要让浏览器正确地显示预留字符,我们必须在 HTML 源代码中使用字符实体(character entities)。
1.2、HTML字符实体,数据的表达
1、&号 “加” 特殊字符的“约定实体名称” “加” ;号,比如符号: < ,表达为: <
注意,实体名称:大小写敏感。或者:
2、&号 “加” # “加” 特殊字符的ASCII码 “加” ;号,比如符号: < ,表达为: <
html保留字的字符实体表:
显示结果 | 描述 | 实体名称 | 实体编号 |
---|---|---|---|
空格 | |   | |
< | 小于号 | < | < |
> | 大于号 | > | > |
& | 和号 | & | & |
" | 引号 | " | " |
' | 撇号 | ' (IE不支持) | ' |
¢ | 分 | ¢ | ¢ |
£ | 镑 | £ | £ |
¥ | 日圆 | ¥ | ¥ |
€ | 欧元 | € | € |
§ | 小节 | § | § |
© | 版权 | © | © |
® | 注册商标 | ® | ® |
™ | 商标 | ™ | ™ |
× | 乘号 | × | × |
÷ | 除号 | ÷ | ÷ |
js中“字面量”字符串转义符:
Code | Output |
---|---|
\0 | 空字符 |
\' | 单引号 |
\" | 双引号 |
\\ | 反斜杠 |
\n | 换行 |
\r | 回车 |
\v | 垂直制表符 |
\t | 水平制表符 |
\b | 退格 |
\f | 换页 |
\uXXXX | unicode 码 |
\u{X} ... \u{XXXXXX} | unicode codepoint Experimental |
\xXX | Latin-1 字符 (x 小写) |
2、URL编码的特殊字符
Percent-encoding也称URL编码。
是一种拥有 8 位字符编码的编码机制,这些编码在URL的上下文中具有特定的含义。它有时被称为 URL 编码。编码由英文字母替换组成:“%” 后跟替换字符的 ASCII 的十六进制表示。
需要编码的特殊字符有:
':'
,'/'
,'?'
,'#'
,'['
,']'
,'@'
,'!'
,'$'
,'&'
,"'"
,'('
,')'
,'*'
,'+'
,','
,';'
,'='
, 以及,'%'
本身,这一点容易被忽视。其他的字符虽然可以进行编码,但是,不需要。
URL encoding character RFC规范 :
An example HTML documenthttps://www.ietf.org/rfc/rfc2396.txt
https://en.wikipedia.org/wiki/Percent-encodinghttps://en.wikipedia.org/wiki/Percent-encoding
2.1、URL支持的字符
由于URL只支持英文字母、数字、横杠、下划线、句点、波浪线,若要表示其他字符则需要编码。
例如:百分号、中文。
由于百分号也需要编码,因此会出现某些绕过问题。
①、URL编码基于ASCII码:
- URL中无特殊字符: 全是ASCII可显示字符
https://www.cpuofbs.com/rest/postdata?A=abc&B=123
https://www.cpuofbs.com/rest/postdata?A=abc&B=123
- URL中包含特殊字符: 空格 、(顿号等等)
https://www.cpuofbs.com/rest/postdata?A= abc&B、=123
https://www.cpuofbs.com/rest/postdata?A=%20abc&B%E3%80%81=123
- URL中包含特殊字符: 中文
https://www.cpuofbs.com/rest/postdata?学生姓名=英文名abc&身份证号sfzh=432345678909876543
https://www.cpuofbs.com/rest/postdata?%E5%AD%A6%E7%94%9F%E5%A7%93%E5%90%8D=%E8%8B%B1%E6%96%87%E5%90%8Dabc&%E8%BA%AB%E4%BB%BD%E8%AF%81%E5%8F%B7sfzh=432345678909876543
②、特殊字符,先根据当前页面的编码方式转换,比如:<meta charset="utf-8" content-type="text/html" />,
取其十六进制形式,每两位添加1个%
␣ | ! | # | $ | % | & | ' | ( | ) | * | + | , | / | : | ; | = | ? | @ | [ | ] |
%20 | %21 | %23 | %24 | %25 | %26 | %27 | %28 | %29 | %2A | %2B | %2C | %2F | %3A | %3B | %3D | %3F | %40 | %5B | %5D |
在特定上下文中没有保留用途的保留字符也可以进行百分比编码,但在语义上与没有保留的字符没有区别。
例如,在 URI的“查询”组件(?
字符之后的部分)中,/
仍被视为保留字符,但它通常没有保留用途,除非特定的 URI 方案另有说明。当字符没有保留用途时,不需要进行百分比编码。
仅通过保留字符是百分比编码还是按字面显示不同的 URI 通常被认为是不等价的(表示相同的资源),除非可以确定所讨论的保留字符没有保留用途。此确定取决于各个 URI 方案为保留字符建立的规则。
根据上下文, 空白符 ' '
将会转换为 '+'
(必须在 HTTP 的 POST 方法中使定义 :application/x-www-form-urlencoded
传输方式), 或者将会转换为 '%20'
的 URL。
以及,'%'
本身,这一点容易被忽视。
2.2、ASCII字符编码表
HTML 和 XHTML 用标准的 7 比特 ASCII 代码在网络上传输数据。
2.2.1、“32~126”区段,可显式区段:
结果 | 描述 | 实体编号 |
---|---|---|
space |   | |
! | exclamation mark | ! |
" | quotation mark | " |
# | number sign | # |
$ | dollar sign | $ |
% | percent sign | % |
& | ampersand | & |
' | apostrophe | ' |
( | left parenthesis | ( |
) | right parenthesis | ) |
* | asterisk | * |
+ | plus sign | + |
, | comma | , |
- | hyphen | - |
. | period | . |
/ | slash | / |
0 | digit 0 | 0 |
1 | digit 1 | 1 |
2 | digit 2 | 2 |
3 | digit 3 | 3 |
4 | digit 4 | 4 |
5 | digit 5 | 5 |
6 | digit 6 | 6 |
7 | digit 7 | 7 |
8 | digit 8 | 8 |
9 | digit 9 | 9 |
: | colon | : |
; | semicolon | ; |
< | less-than | < |
= | equals-to | = |
> | greater-than | > |
? | question mark | ? |
@ | at sign | @ |
A | uppercase A | A |
B | uppercase B | B |
C | uppercase C | C |
D | uppercase D | D |
E | uppercase E | E |
F | uppercase F | F |
G | uppercase G | G |
H | uppercase H | H |
I | uppercase I | I |
J | uppercase J | J |
K | uppercase K | K |
L | uppercase L | L |
M | uppercase M | M |
N | uppercase N | N |
O | uppercase O | O |
P | uppercase P | P |
Q | uppercase Q | Q |
R | uppercase R | R |
S | uppercase S | S |
T | uppercase T | T |
U | uppercase U | U |
V | uppercase V | V |
W | uppercase W | W |
X | uppercase X | X |
Y | uppercase Y | Y |
Z | uppercase Z | Z |
[ | left square bracket | [ |
\ | backslash | \ |
] | right square bracket | ] |
^ | caret | ^ |
_ | underscore | _ |
` | grave accent | ` |
a | lowercase a | a |
b | lowercase b | b |
c | lowercase c | c |
d | lowercase d | d |
e | lowercase e | e |
f | lowercase f | f |
g | lowercase g | g |
h | lowercase h | h |
i | lowercase i | i |
j | lowercase j | j |
k | lowercase k | k |
l | lowercase l | l |
m | lowercase m | m |
n | lowercase n | n |
o | lowercase o | o |
p | lowercase p | p |
q | lowercase q | q |
r | lowercase r | r |
s | lowercase s | s |
t | lowercase t | t |
u | lowercase u | u |
v | lowercase v | v |
w | lowercase w | w |
x | lowercase x | x |
y | lowercase y | y |
z | lowercase z | z |
{ | left curly brace | { |
| | vertical bar | | |
} | right curly brace | } |
~ | tilde | ~ |
2.2.2、“0~30及独立的127”区段,设备控制区段:
ASCII设备控制代码最初被设计为用来控制诸如打印机和磁带驱动器之类的硬件设备。在HTML文档中这些代码不会起任何作用:
结果 | 描述 | 实体编号 |
---|---|---|
NUL | null character | � |
SOH | start of header |  |
STX | start of text |  |
ETX | end of text |  |
EOT | end of transmission |  |
ENQ | enquiry |  |
ACK | acknowledge |  |
BEL | bell (ring) |  |
BS | backspace |  |
HT | horizontal tab | 	 |
LF | line feed | |
VT | vertical tab |  |
FF | form feed |  |
CR | carriage return | |
SO | shift out |  |
SI | shift in |  |
DLE | data link escape |  |
DC1 | device control 1 |  |
DC2 | device control 2 |  |
DC3 | device control 3 |  |
DC4 | device control 4 |  |
NAK | negative acknowledge |  |
SYN | synchronize |  |
ETB | end transmission block |  |
CAN | cancel |  |
EM | end of medium |  |
SUB | substitute |  |
ESC | escape |  |
FS | file separator |  |
GS | group separator |  |
RS | record separator |  |
US | unit separator |  |
DEL | delete (rubout) |  |
3、Base64编码的特殊字符
Base64 encoding character
3.1、base64在http和html中有许多使用场景:
1、比如我们在html中表达1个图片文件进行base64编码的src资源,可以:
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAE0lEQVQImWP4f4bLly//BwAmVgd1/w11/gAAAABJRU5ErkJggg==
2、再比如 对文件进行base64编码,我们上传和下载超大文件,可先对其进行base64二进制编码再压缩后,进行,这样可以极大提升效率并提供了“断点”续传的可能
3.2、base64字符编码表
大写A~Z ,小写a~z , 数字0~9, + \ ,以及1个特殊的“字符A”结尾标识符 ==
6位二进制补齐后的10进制索引
|
base64
字符
| 6位二进制补齐后的10进制索引 | base64字符 | 6位二进制补齐后的10进制索引 | base64字符 | 6位二进制补齐后的10进制索引 | base64字符 |
0
|
A
|
16
|
Q
|
32
|
g
|
48
|
w
|
1
|
B
|
17
|
R
|
33
|
h
|
49
|
x
|
2
|
C
|
18
|
S
|
34
|
i
|
50
|
y
|
3
|
D
|
19
|
T
|
35
|
j
|
51
|
z
|
4
|
E
|
20
|
U
|
36
|
k
|
52
|
0
|
5
|
F
|
21
|
V
|
37
|
l
|
53
|
1
|
6
|
G
|
22
|
W
|
38
|
m
|
54
|
2
|
7
|
H
|
23
|
X
|
39
|
n
|
55
|
3
|
8
|
I
|
24
|
Y
|
40
|
o
|
56
|
4
|
9
|
J
|
25
|
Z
|
41
|
p
|
57
|
5
|
10
|
K
|
26
|
a
|
42
|
q
|
58
|
6
|
11
|
L
|
27
|
b
|
43
|
r
|
59
|
7
|
12
|
M
|
28
|
c
|
44
|
s
|
60
|
8
|
13
|
N
|
29
|
d
|
45
|
t
|
61
|
9
|
14
|
O
|
30
|
e
|
46
|
u
|
62
|
+
|
15
|
P
|
31
|
f
|
47
|
v
|
63
|
/
|
base64字符索引、二进制、base64字符 对照表:
索引 | 2进制 | Char | 索引 | 2进制 | Char | 索引 | 2进制 | Char | 索引 | 2进制 | Char | |||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 000000 | A | 16 | 010000 | Q | 32 | 100000 | g | 48 | 110000 | w | |||
1 | 000001 | B | 17 | 010001 | R | 33 | 100001 | h | 49 | 110001 | x | |||
2 | 000010 | C | 18 | 010010 | S | 34 | 100010 | i | 50 | 110010 | y | |||
3 | 000011 | D | 19 | 010011 | T | 35 | 100011 | j | 51 | 110011 | z | |||
4 | 000100 | E | 20 | 010100 | U | 36 | 100100 | k | 52 | 110100 | 0 | |||
5 | 000101 | F | 21 | 010101 | V | 37 | 100101 | l | 53 | 110101 | 1 | |||
6 | 000110 | G | 22 | 010110 | W | 38 | 100110 | m | 54 | 110110 | 2 | |||
7 | 000111 | H | 23 | 010111 | X | 39 | 100111 | n | 55 | 110111 | 3 | |||
8 | 001000 | I | 24 | 011000 | Y | 40 | 101000 | o | 56 | 111000 | 4 | |||
9 | 001001 | J | 25 | 011001 | Z | 41 | 101001 | p | 57 | 111001 | 5 | |||
10 | 001010 | K | 26 | 011010 | a | 42 | 101010 | q | 58 | 111010 | 6 | |||
11 | 001011 | L | 27 | 011011 | b | 43 | 101011 | r | 59 | 111011 | 7 | |||
12 | 001100 | M | 28 | 011100 | c | 44 | 101100 | s | 60 | 111100 | 8 | |||
13 | 001101 | N | 29 | 011101 | d | 45 | 101101 | t | 61 | 111101 | 9 | |||
14 | 001110 | O | 30 | 011110 | e | 46 | 101110 | u | 62 | 111110 | + | |||
15 | 001111 | P | 31 | 011111 | f | 47 | 101111 | v | 63 | 111111 | / | |||
Padding 填充位 | = |
代码表示Base64字符表:
Shotgun.Js.Base64 = {
_table: [
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
],
3.3、base64字节规则及编码步骤
3.3.1、内存中,字节的编组方式
通常,计算机的内存中用8位二进制表达1个字符。
比如10进制数65对应的字符A ,内存中8位表示:0100 0001 :
用24位表示,尾随两个”空字符“NUL (NULL),表示为:
01000001 00000000 00000000
3.3.2、base64的字符内存编组方式
上述,ASC码表中,每3个字符将被编码为4个字符(3×8 → 4×6);不满4个字符的位,编组完后,以Base64的'='符号做填充:
3组变4组,将原本3*8=24位,改编为4*6(其中含2位补齐)=24位
比如上述字符A :0100 0001 :
01000001,从低位开始,6位为1组,尾部补齐:
0001 000000 010000
即:00010000 00010000
查找ASCII编码表10进制结果:16 16
或(标准格式):
00010000 00010000 00000000 00000000
16 16 NUL(null) NUL(null)
然后,根据该10进制,比照base64字符编码表的索引:
字符A重新编组后:
16 16
对应Base64的Char字符的结果是:
Q Q
或(标准格式):
16 16 NUL(null) NUL(null) ---------00000000 00000000刚好比对出2个“A”则用==表示:
QQ==
又比如,字符B:0100 0010 :
0100 000000 000000 100000
00010000 00000000 00100000
16 32
Q g
结果: Qg==
以上为”单字节“,那么如何处理”多字节“,先看案例:
//
window.btoa('B')
'Qg=='
window.btoa('BC')
'QkM='
window.btoa('BCD')
'QkNE'
window.btoa('BCDE')
'QkNERQ=='
window.btoa('BCDEF')
'QkNERUY='
window.btoa('BCDEFG')
'QkNERUZH'
//
规律:1、每3个字节,变成了4个字节;2、重新编组后的字节总数,一定能被4整除,即:4位为1组。
推导:1、只要遇到6位1组的多字节,其按Base64重新编组的结果,就不会产生填充符”=“ ;
3.3.3、js中base64的编码和解码:
// 解决方案 #1 – 在编码之前转义字符串---unescape和escape已弃用 :
function utf8_to_b64(str) {
return window.btoa(unescape(encodeURIComponent(str)));
}; //
function b64_to_utf8(str) {
return decodeURIComponent(escape(window.atob(str)));
}; //
const bin8 = '01000001', // 00010000 00010000
bin16 = '0001000000010000', // 00010000 00010000 代表QQ
bin32 = '00010000000100000000000000000000'; // 00010000 00010000 00000000 00000000 代表QQ==
//
//00010000 00010000
let encodedData = window.btoa("A"); // = Base64编码 (缺陷)
console.log(encodedData); //: QQ==
let decodedData = window.atob("QQ=="); // = ASCII编码 (缺陷)
let decodedData_2 = window.atob("QQ=="); // = ASCII编码 (缺陷)
console.log(decodedData); //:
console.log(utf8_to_b64("A")); //: (缺陷)
console.log(b64_to_utf8("QQ==")); //: 必须2**n幂等 //console.log(2 ** 4);//: 2**n幂运算
console.log(b64_to_utf8("QQ")); //: (缺陷)
//
//解决方案 #2 – 重写atob()和btoa()使用TypedArrays 和 UTF-8 :
//注意:以下代码对于从 Base64 字符串获取ArrayBuffer也很有用,反之亦然(见下文):
//
"use strict";
// 字节数组到Base64字符串解码 :
function b64ToUint6(nChr) {
return nChr > 64 && nChr < 91 ?
nChr - 65 :
nChr > 96 && nChr < 123 ?
nChr - 71 :
nChr > 47 && nChr < 58 ?
nChr + 4 :
nChr === 43 ?
62 :
nChr === 47 ?
63 :
0;
}
function base64DecToArr(sBase64, nBlocksSize) {
const sB64Enc = sBase64.replace(/[^A-Za-z0-9+/]/g, "");
const nInLen = sB64Enc.length;
const nOutLen = nBlocksSize ? Math.ceil((nInLen * 3 + 1 >> 2) / nBlocksSize) * nBlocksSize : nInLen * 3 + 1 >> 2;
const taBytes = new Uint8Array(nOutLen);
let nMod3;
let nMod4;
let nUint24 = 0;
let nOutIdx = 0; //let nOutId = 0;
for (let nInIdx = 0; nInIdx < nInLen; nInIdx++) {
nMod4 = nInIdx & 3;
nUint24 |= b64ToUint6(sB64Enc.charCodeAt(nInIdx)) << 6 * (3 - nMod4);
if (nMod4 === 3 || nInLen - nInIdx === 1) {
nMod3 = 0;
while (nMod3 < 3 && nOutIdx < nOutLen) {
taBytes[nOutIdx] = nUint24 >>> (16 >>> nMod3 & 24) & 255;
nMod3++;
nOutIdx++;
}
nUint24 = 0;
}
}
return taBytes;
}
/* Base64字符串到数组编码 : */
function uint6ToB64(nUint6) {
return nUint6 < 26 ?
nUint6 + 65 :
nUint6 < 52 ?
nUint6 + 71 :
nUint6 < 62 ?
nUint6 - 4 :
nUint6 === 62 ?
43 :
nUint6 === 63 ?
47 :
65;
}
function base64EncArr(aBytes) {
let nMod3 = 2;
let sB64Enc = "";
const nLen = aBytes.length;
let nUint24 = 0;
for (let nIdx = 0; nIdx < nLen; nIdx++) {
nMod3 = nIdx % 3;
if (nIdx > 0 && (nIdx * 4 / 3) % 76 === 0) {
sB64Enc += "\r\n";
}
nUint24 |= aBytes[nIdx] << (16 >>> nMod3 & 24);
if (nMod3 === 2 || aBytes.length - nIdx === 1) {
sB64Enc += String.fromCodePoint(uint6ToB64(nUint24 >>> 18 & 63), uint6ToB64(nUint24 >>> 12 & 63), uint6ToB64(nUint24 >>> 6 & 63), uint6ToB64(nUint24 & 63));
nUint24 = 0;
}
}
return sB64Enc.substr(0, sB64Enc.length - 2 + nMod3) + (nMod3 === 2 ? '' : nMod3 === 1 ? '=' : '==');
}
/* UTF-8数组到JS字符串,反之亦然 : */
function UTF8ArrToStr(aBytes) {
let sView = "";
let nPart;
const nLen = aBytes.length;
for (let nIdx = 0; nIdx < nLen; nIdx++) {
nPart = aBytes[nIdx];
sView += String.fromCodePoint(
nPart > 251 && nPart < 254 && nIdx + 5 < nLen ? /* six bytes */
/* (nPart - 252 << 30) may be not so safe in ECMAScript! So…: */
(nPart - 252) * 1073741824 + (aBytes[++nIdx] - 128 << 24) + (aBytes[++nIdx] - 128 << 18) + (aBytes[++nIdx] - 128 << 12) + (aBytes[++nIdx] - 128 << 6) + aBytes[++nIdx] - 128 :
nPart > 247 && nPart < 252 && nIdx + 4 < nLen ? /* five bytes */
(nPart - 248 << 24) + (aBytes[++nIdx] - 128 << 18) + (aBytes[++nIdx] - 128 << 12) + (aBytes[++nIdx] - 128 << 6) + aBytes[++nIdx] - 128 :
nPart > 239 && nPart < 248 && nIdx + 3 < nLen ? /* four bytes */
(nPart - 240 << 18) + (aBytes[++nIdx] - 128 << 12) + (aBytes[++nIdx] - 128 << 6) + aBytes[++nIdx] - 128 :
nPart > 223 && nPart < 240 && nIdx + 2 < nLen ? /* three bytes */
(nPart - 224 << 12) + (aBytes[++nIdx] - 128 << 6) + aBytes[++nIdx] - 128 :
nPart > 191 && nPart < 224 && nIdx + 1 < nLen ? /* two bytes */
(nPart - 192 << 6) + aBytes[++nIdx] - 128 :
/* nPart < 127 ? */
/* one byte */
nPart
);
}
return sView;
}
function strToUTF8Arr(sDOMStr) {
let aBytes;
let nChr;
const nStrLen = sDOMStr.length;
let nArrLen = 0;
/* mapping… */
for (let nMapIdx = 0; nMapIdx < nStrLen; nMapIdx++) {
nChr = sDOMStr.codePointAt(nMapIdx);
if (nChr > 65536) {
nMapIdx++;
}
nArrLen += nChr < 0x80 ? 1 : nChr < 0x800 ? 2 : nChr < 0x10000 ? 3 : nChr < 0x200000 ? 4 : nChr < 0x4000000 ? 5 : 6;
}
aBytes = new Uint8Array(nArrLen);
/* 转录 : transcription… */
let nIdx = 0;
let nChrIdx = 0;
while (nIdx < nArrLen) {
nChr = sDOMStr.codePointAt(nChrIdx);
if (nChr < 128) {
/* one byte */
aBytes[nIdx++] = nChr;
} else if (nChr < 0x800) {
/* two bytes */
aBytes[nIdx++] = 192 + (nChr >>> 6);
aBytes[nIdx++] = 128 + (nChr & 63);
} else if (nChr < 0x10000) {
/* three bytes */
aBytes[nIdx++] = 224 + (nChr >>> 12);
aBytes[nIdx++] = 128 + (nChr >>> 6 & 63);
aBytes[nIdx++] = 128 + (nChr & 63);
} else if (nChr < 0x200000) {
/* four bytes */
aBytes[nIdx++] = 240 + (nChr >>> 18);
aBytes[nIdx++] = 128 + (nChr >>> 12 & 63);
aBytes[nIdx++] = 128 + (nChr >>> 6 & 63);
aBytes[nIdx++] = 128 + (nChr & 63);
nChrIdx++;
} else if (nChr < 0x4000000) {
/* five bytes */
aBytes[nIdx++] = 248 + (nChr >>> 24);
aBytes[nIdx++] = 128 + (nChr >>> 18 & 63);
aBytes[nIdx++] = 128 + (nChr >>> 12 & 63);
aBytes[nIdx++] = 128 + (nChr >>> 6 & 63);
aBytes[nIdx++] = 128 + (nChr & 63);
nChrIdx++;
} else /* if (nChr <= 0x7fffffff) */ {
/* six bytes */
aBytes[nIdx++] = 252 + (nChr >>> 30);
aBytes[nIdx++] = 128 + (nChr >>> 24 & 63);
aBytes[nIdx++] = 128 + (nChr >>> 18 & 63);
aBytes[nIdx++] = 128 + (nChr >>> 12 & 63);
aBytes[nIdx++] = 128 + (nChr >>> 6 & 63);
aBytes[nIdx++] = 128 + (nChr & 63);
nChrIdx++;
}
nChrIdx++;
}
return aBytes;
}
// 测试 :
const sMyInput = "Base 64 \u2014 ";
const aMyUTF8Input = strToUTF8Arr(sMyInput);
const sMyBase64 = base64EncArr(aMyUTF8Input);
console.log(sMyBase64);
//
const aMyUTF8Output = base64DecToArr(sMyBase64);
const sMyOutput = UTF8ArrToStr(aMyUTF8Output);
console.log(sMyOutput);
//
const sMyInput_ = "\ud869\ude95\u3400\u499b\u2a6c7\udec7";
const aMyUTF8Input_ = strToUTF8Arr(sMyInput);
const sMyBase64_ = base64EncArr(aMyUTF8Input);
console.log(sMyBase64_);
// 👪 \ 转义符: (€) € € < < &(&) (") 表示为" 将单引号 (') 表示为'
//👨‍👩‍👧‍👦为了表达'\u1F468\u200D\u1F469\u200D\u1F467\u200D\u1F466'使用16进制或10进制
//��㐀䦛𪛇�
//𪛇 ; 𣎴 关于UTF-16补充字符与码点 :使用UCS4高低位转换计算后的码点"𣎴"而不是UTF-16的高低位码: ��
//
// 将 Base64 字符串解码为 Uint8Array 或 ArrayBuffer :
//函数base64DecToArr(sBase64[, nBlockSize])返回一个uint8字节数组。
//如果您的目标是构建16位/32位/64位原始数据的缓冲区,请使用nBlockSize参数(幂等参数) : 这是uint8Array.buffer所包含的字节数 :
//uint8Array.buffer.bytesLength属性:
//1、ASCII二进制字符(即字符串中的每个字符都被视为二进制数据8位1个字节的字符)
//2、或UTF-8编码字符串为1个8位,UTF-16字符串为2个8位,UTF-32字符串为4个8位。
// : 字符编码 :
//
// "Base 64 \u2014 Mozilla Developer Network"
const myArray = base64DecToArr("QmFzZSA2NCDigJQgTW96aWxsYSBEZXZlbG9wZXIgTmV0d29yaw==");
// "Base 64 \u2014 " // : \u2014字节长3 : \u占1个字节、全角字符-占2个字节
const myBuffer = base64DecToArr("QmFzZSA2NCDigJQgTW96aWxsYSBEZXZlbG9wZXIgTmV0d29yaw==").buffer;
console.log(myBuffer.byteLength); //:
//当您从服务器检索文档时,服务器通常会随文档发送一些附加信息。这称为 HTTP 标头。这是一个关于文档信息的示例,该信息通过 HTTP 标头与文档一起从服务器传输到客户端时传递