目录
http通讯及浏览器中的HTML编码、URL编码、base64编码及转义
HTML encoding character
HTML 和 XHTML 用标准的 7 比特 ASCII 代码在网络上传输数据。
HTML语言 中的“保留字”,即某些预留字符。
比如:不能在除“元素”意外的位置,使用小于号(<)和大于号(>),浏览器会误解为它们是标签。
若有需要让浏览器正确地显示预留字符,我们必须在 HTML 源代码中使用字符实体(character entities)。
1、&号 “加” 特殊字符的“约定实体名称” “加” ;号,比如符号: < ,表达为: <
注意,实体名称:大小写敏感。或者:
2、&号 “加” # “加” 特殊字符的ASCII码 “加” ;号,比如符号: < ,表达为: <
html保留字的字符实体表:
| 显示结果 | 描述 | 实体名称 | 实体编号 |
|---|---|---|---|
| 空格 | |||
| < | 小于号 | < | < |
| > | 大于号 | > | > |
| & | 和号 | & | & |
| " | 引号 | " | " |
| ' | 撇号 | ' (IE不支持) | ' |
| ¢ | 分 | ¢ | ¢ |
| £ | 镑 | £ | £ |
| ¥ | 日圆 | ¥ | ¥ |
| € | 欧元 | € | € |
| § | 小节 | § | § |
| © | 版权 | © | © |
| ® | 注册商标 | ® | ® |
| ™ | 商标 | ™ | ™ |
| × | 乘号 | × | × |
| ÷ | 除号 | ÷ | ÷ |
URL encoding character
由于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
②、特殊字符,先根据当前页面的编码方式转换,比如:,
取其十六进制形式,每两位添加1个%
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) | |
Base64 encoding character
1、比如我们在html中表达1个图片文件进行base64编码的src资源,可以:
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAE0lEQVQImWP4f4bLly//BwAmVgd1/w11/gAAAABJRU5ErkJggg==

2、再比如 对文件进行base64编码,我们上传和下载超大文件,可先对其进行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.1、非base64的字符内存编组方式
通常,计算机的内存中用8位二进制表达1个字符。
比如字符A :0100 0001 :
01000001
3.3.2、base64的字符内存编组方式
将原本1*8=8,改编为2*(2补齐+6)=16
比如字符A :
00010000 00010000
查找ASCII表10进制结果:
16 16
或(标准格式):
00010000 00010000 00000000 00000000
16 16 NUL(null) NUL(null)
然后,比照base64字符编码表:
16 16
结果:
或(标准格式):
16 16 NUL(null) NUL(null) ---------00000000 00000000刚好比对出2个“A”则用==表示:
QQ==
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 标头与文档一起从服务器传输到客户端时传递
-
-