base64

定义

百度百科对base64的定义:Base64是网络上最常见的用于传输8Bit字节码的编码方式之一,Base64就是一种基于64个可打印字符来表示二进制数据的方法。

传输数据为什么需要编码?数据在网络中传输一定是以字节码形式传输的,A端发送数据data给B端,由于A发送的是字符数据,在进行网络传输前数据必须被编码成字节数据,这就涉及到编码问题。

为什么要将字节码编码成64个可打印字符进行传输?编码也是有讲究的,在有些文本传输协议中,如果直接将字符完整编码为对应的字节序列就可能出现问题,因为编码出来的字节序列中可能存在文本传输协议的控制信息,这样就会破坏应用层协议传输数据。出现这种问题的根源在于编码后的字节中出现了不可见字符(128-255的asc码),如果能够将字符全部编码为可见字符(字母、符号),这种问题就可以得到解决,Base64就这样的一种编码方式。

 

编码逻辑

Base64顾名思义就只有64个字符,产生64个字符就需要6bit,而一个字节是8bit,故需要对原字节拆分。如下图,3个字节正好可以拆分成4组6bit,再将每组6bit的高2位补0,就产生了新的8bit字节,新字节一定是可见字符(0-63的asc码)。如果字节数不能被正好拆分,比如1个字节,就需要使用=来占位(=只可能是0个、1个或2个,=也是可见字符,所以是安全的。之所以要补充=,猜测是因为base64在解码时是4个字节一组进行解码的,所以才必须补全)。

 

base64的64个字符是['A', 'B', 'C', ... 'a', 'b', 'c', ... '0', '1', ... '+', '/']

 

Example

“abcd”的字节序列

01100001  01100010  01100011  01100100 

Base64编码后

00011000  00010110  00001001  00100011  00011001  00000000

对照Base64字符集

YWJjZA

补=

YWJjZA==

 

HTTP中的编码

之前提到base64适合在文本传输协议中传输二进制数据,http属于典型的文本传输协议,http中有必要使用base64吗?

我们可以通过http上传文件,来看http是如何处理文件上传的。

在上传图片、文件等二进制数据时,http请求大致是下面的格式:

POST /t2/upload.do HTTP/1.1
User-Agent: xyz
Accept-Language: zh-cn,zh;q=0.5
Accept-Charset: GBK,utf-8;q=0.7,*;q=0.7
Connection: keep-alive
Content-Length: 60408
Content-Type:multipart/form-data; boundary=ZnGpDtePMx0KrHh_G0X99Yef9r8JZsRJSXC
Host: www.xyz.com
 
--ZnGpDtePMx0KrHh_G0X99Yef9r8JZsRJSXC
Content-Disposition: form-data;name="desc"
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
 
name=zhang3
--ZnGpDtePMx0KrHh_G0X99Yef9r8JZsRJSXC
Content-Disposition: form-data;name="pic"; filename="photo.jpg"
Content-Type: application/octet-stream
Content-Transfer-Encoding: binary
 
[图片二进制数据]
--ZnGpDtePMx0KrHh_G0X99Yef9r8JZsRJSXC--

可以发现,http传输图片、文件时并不需要base64编码,因为其对这类二进制数据有专门的协议约束(application/octet-stream、boundary),此时即便存在不可见字符,也不会威胁到协议本身(当然可以手动进行base64编码)。 

是不是说http就不需要编码了呢?文本传输都需要编码字符序列,http在传输参数时会使用url编码,其实就是%+utf-8编码的十六进制,由于%的存在(可见字符),其仍然是安全的。

 

 

附:自己实现的base64编码,使用3字节一组进行编码应该会好些。

 1     public class Base64Encoder {
 2         private byte[] bytes;
 3         private static Map<Byte, Character> base64;
 4         static {
 5             base64 = new HashMap<>();
 6             int i = 0;
 7             for(; i<26; i++) {
 8                 base64.put((byte) i, Character.valueOf((char) ('A' + i)));
 9             }
10             for(; i<52; i++) {
11                 base64.put((byte) i, Character.valueOf((char) ('a' + i-26)));
12             }
13             base64.put((byte) i++, '+');
14             base64.put((byte) i, '/');
15         }
16 
17         public Base64Encoder(String s, Charset charset) {
18             bytes = s.getBytes(charset);
19         }
20         public char[] toBase64() {
21             int length = bytes.length;
22             char[] base64Chars = new char[(length % 3 == 0 ? length / 3 * 4 : (length / 3 * 4 + 4))];
23             for(int i=0; i<length; i++) {
24                 base64Chars[i] = nextBase64Char(i);
25             }
26             return base64Chars;
27         }
28 
29         /**
30          * 产生bytes中索引为i的base64字符,
31          * @param i
32          * @return
33          */
34         private char nextBase64Char(int i) {
35             i = i*6;
36             int index = i/8;
37             int offset = i%8;
38             Character c;
39             if (index < bytes.length) {
40                 byte b = nextBase64Byte(index, offset);
41                 System.out.print(Integer.toBinaryString(b) + " ");
42                 c = base64.get(b);
43             }else {
44                 c = '=';
45             }
46             return c;
47         }
48 
49         /**
50          * 从bytes中得到索引为index,偏移量为offset的base64字节
51          * @param index
52          * @param offset
53          * @return
54          */
55         private byte nextBase64Byte(int index, int offset) {
56             byte b = bytes[index];
57             byte result = 0;
58             b = (byte) (b<<offset);
59             b = (byte) ((0xFF&b)>>>2);
60             if (offset <= 2) {
61                 return b;
62             }
63             result |= b;
64             if (++index < bytes.length) {
65                 b = bytes[index];
66                 result |= (0xFF&b) >>> (10 - offset);
67             }
68             return result;
69         }
70     }
View Code

 

posted @ 2017-08-17 16:25  holoyong  阅读(1265)  评论(0编辑  收藏  举报