Base64是什么?

Base64是一种二进制到文本的编码方式,常用于解决不同系统及传输协议中二进制数据的不兼容问题。它将数据拆分为6位一组,映射到64个ASCII字符中,编码后数据长度为原来的4/3。Base64编码适用于证书、电子邮件附件、XML数据嵌入、网页图片等内容的传输,且有多种变种适应不同场景需求。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Base64是什么?

Base64是一种二进制到文本的编码方式。如果要更具体一点的话,可以认为它是一种将 byte数组编码为字符串的方法,而且编码出的字符串只包含ASCII基础字符。

例如字符串ShuSheng007对应的Base64为U2h1U2hlbmcwMDc=。其中那个=比较特殊,是填充符,一会再说。

值得注意的是Base64不是加密算法,其仅仅是一种编码方式,算法也是公开的,所以不能依赖它进行加密。

为什么叫Base64?

因为它是基于(Base)64个字符的一种编码方式。使用其编码后的文本只包含64个ASCII码字符(偶尔加一个填充字符=),如下所示:

Base64使用到的64个字符:

  • A-Z 26个
  • a-z 26个
  • 0-9 10个
  • + 1个
  • / 1个

下图是Base64码表,可以看到从0到63的每个数字都对应一个上面的一个字符。img

Base64解决什么问题?

Base64编码是从二进制值到某些特定字符的编码,这些特定字符一共64个,所以称作Base64。

为什么不直接传输二进制呢?比如图片,或者字符,既然实际传输时它们都是二进制字节流。而且即使Base64编码过的字符串最终也是二进制(通常是UTF-8编码,兼容ASCII编码)在网络上传输的,那么用4/3倍带宽传输数据的Base64究竟有什么意义?

真正的原因是二进制不兼容。某些二进制值,在一些硬件上,比如在不同的路由器,老电脑上,表示的意义不一样,做的处理也不一样。同样,一些老的软件,网络协议也有类似的问题。

在项目中,对报文进行压缩、加密后,最后一步一般是 base64 编码。因为 base64 编码的字符串更适合不同平台,不同语言的传输。

base64 编码的优点:

  • 算法是编码,不是压缩,编码后只会增加字节数(一般是比之前的多1/3,比如之前是3, 编码后是4)
  • 算法简单,基本不影响效率
  • 算法可逆,解码很方便,不用于私密传输。
  • 毕竟编码了,肉眼不能直接读出原始内容。
  • 加密后的字符串只有【0-9a-zA-Z+/=】 不可打印字符(转译字符)也可以传输

Base64就是为了解决各系统以及传输协议中二进制不兼容的问题而生的

//二进制数据传输过程中,不可见字符或者无法由UTF-8解码的二进制数据(一个字符对应一个二进制编码,但是一个二进制不一定能对应上一个字符),数据可能丢失 
public static void main(String[] args) {
        //字节数组,经常用来表示二进制数据
        byte[] bytes1 = new byte[]{31, -117, 8};
        //直接用字符串来转换字节数组(默认UTF-8编码)
        String str = new String(bytes1);
        System.out.println(str);//
        byte[] bytes2 = str.getBytes();
        System.out.println(Arrays.toString(bytes2)); //结果[31, -17, -65, -67, 8] 和原来的bytes1:[31,-117,8]并不相同
        //这是为什么呢?
        //UTF-8编码是一种变长编码,一个字符对应一个二进制编码,但是一个二进制不一定能对应上一个字符
        //如果采用 Ascii码(UTF-8兼容)中的数据,就可以完成映射,并且不丢失数据
        byte[] bytes3 = new byte[]{49, 50, 51};
        String str2 = new String(bytes3);
        System.out.println(str2);
        byte[] bytes4 = str2.getBytes();
        System.out.println(Arrays.toString(bytes4));//结果:[49, 50, 51] 和 bytes3[49,50,51]就相同了
        //其它的大多数编码方法,都是一个字符对应一个二进制编码,但是一个二进制编码不一定呢个对应上一个字符
        //但是Base64可以,是如何解决的呢?
        //Base64,采用6位一个单元,去Ascii中取出了64个可见字符来做映射(A-Z a-z 0-9 + /),
        // 这样所有的二进制都能根据长度分割为每6位对应一个字符,不够6的倍数会用 0补全, 如果6位都是0,则映射为 = 号
        //通过Base64编码后
        String encode = Base64.encode(bytes1);
        System.out.println(encode);//H4sI
        byte[] decode = Base64.decode(encode);
        System.out.println(Arrays.toString(decode));//结果:[31, -117, 8] 和原来的bytes1:[31,-117,8]相同了
    }

编码Man

image-20220211230134264

三个字符Man编码后为四个字符TWFu

由此看出原数据一个字节需要8位,base64编码需要6位,所以原数据字节数必须是8与6的公约数,也就是3的倍数

当然如果要需要编码的字节数不是3的倍数,就需要多出1或2个字节,那么可以使用下面的方法进行处理:先使用0字节值在末尾补足,使其能够被3整除,然后再进行Base64的编码。在编码后的Base64文本后加上一个或两个 = 号,代表补足的字节数。也就是说,当最后剩余两个八位(待补足)字节(2个byte)时,最后一个6位的Base64字节块有四位(2*6-8=4)是0值,最后附加上两个等号;如果最后剩余一个八位(待补足)字节(1个byte)时,最后一个6位的base字节块有两位(3*6-2*8=2)是0值,最后附加一个等号。 参考下表:

image-20220211231052335

所以Base64编码后的数据比原数据略长,为原来的4/3.

Base64 DataURI格式

有时你会发现web页面传给你的base64字符串前面有类似下面的东东。

data:image/jpeg;base64,    /9j/4AA...

这是DataURI,大部分浏览器支持直接打开这类二进制数据,但是我们要格外注意,如果你只是想要真实的Base64内容就需要取,后边的内容

Base64变种

Base64编码可用于在HTTP环境下传递较长的标识信息。例如,在Java持久化系统Hibernate中,就采用了Base64来将一个较长的唯一标识符(一般为128-bit的UUID)编码为一个字符串,用作HTTP表单和HTTP GET URL中的参数。在其他应用程序中,也常常需要把二进制数据编码为适合放在URL(包括隐藏表单域)中的形式。此时,采用Base64编码不仅比较简短,同时也具有不可读性,即所编码的数据不会被人用肉眼所直接看到。

然而,标准的Base64并不适合直接放在URL里传输,因为URL编码器会把标准Base64中的/+字符变为形如%XX的形式,而这些%号在存入数据库时还需要再进行转换,因为ANSI SQL中已将%号用作通配符。

为解决此问题,可采用一种用于URL的改进Base64编码,它不在末尾填充=号,并将标准Base64中的+/分别改成了-_,这样就免去了在URL编解码和数据库存储时所要做的转换,避免了编码信息长度在此过程中的增加,并统一了数据库、表单等处对象标识符的格式。

另有一种用于正则表达式的改进Base64变种,它将+/改成了!-,因为+*以及前面在IRCu中用到的[]正则表达式中都可能具有特殊含义。

此外还有一些变种,它们将+/改为_-._(用作编程语言中的标识符名称)或.-(用于XML中的Nmtoken)甚至_:(用于XML中的Name)。

用途

  • 对于证书来说,尤其是根证书,一般是 base64 编码的,在网上被很多人下载
  • 电子邮件的附件一般是 base64 编码,因为附件往往有不可见字符
  • xml 中如果像嵌入另外一个 xml 文件,直接嵌入,往往 xml 标签就乱套了, 不容易解析,因此,需要把 xml 编译成字节数组的字符串,编译成可见字符。
  • 网页中的一些小图片,可以直接以 base64 编码的方式嵌入,不用再链接请求消耗网络资源。
    外一个 xml 文件,直接嵌入,往往 xml 标签就乱套了, 不容易解析,因此,需要把 xml 编译成字节数组的字符串,编译成可见字符。
  • 网页中的一些小图片,可以直接以 base64 编码的方式嵌入,不用再链接请求消耗网络资源。
  • 较老的纯文本协议 SMTP ,这些文本偶尔传输一个文件时,需要用 base64
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值