zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    Emgu安装配置及使用
    ASP.NET动态网站制作(1)--html
    ASP.NET动态网站制作(0)
    文件自动拆分
    visual studio 常用快捷键
    用vector构造自动扩容的二维数组
    C++中的struct
    Word论文写作如何实现公式居中、编号右对齐
    借助 Filter 生成静态页面缓存问题
    xshell 中解决中文乱码问题
  • 原文地址:https://www.cnblogs.com/holoyong/p/7382319.html
Copyright © 2011-2022 走看看