Base64编码知识详解

更新日期: 2022-06-14阅读: 1.2k标签: 编码

在我们进行前端开发时,针对项目优化,常会提到一条:针对较小图片,合理使用Base64字符串替换内嵌,可以减少页面http请求。
并且还会特别强调下,必须是小图片,大小不要超过多少KB,等等。
那么,Base64又到底是什么呢?

初步认识

下面的这段字符串,应该是大家都很常见的。通过这种固定的格式,来表示一张图片,并被浏览器识别,可以完整的展示出图片:

data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0c......
这里展示的是一个svg格式的图片,当然我们还可以加载任何浏览器支持的格式的图片。

这段字符串就是基于Base64编码得来的,其中base64,后面那一长串的字符串,就是Base64编码字符串。

Base64是怎么诞生的

互联网发展早起,电子邮件是最有效的应用。
而电子邮件的SMTP传输协议在早期,只能用于传送7位的ASCII码,而ASCII码就是基于英语设计的,对于非英语国家的文字等资源就无法发送。
为了解决这个问题,后来有了通用互联网邮件扩充MIME,增加了邮件的主体结构,定义了非ASCII码的编码传输规则,这就是Base64。
关于字符编码的知识,请查看前端开发中需要搞懂的字符编码知识

基础定义

Base64是基于64个可打印字符来表示二进制数据的编解码方式。
正因为可编解码,所以它主要的作用不在于安全性,而在于让内容能在各个网关间无错的传输。

这64个可打印字符包括大写字母A-Z、小写字母a-z、数字0-9共62个字符,再加上另外2个 + 和 /。
Base64是一种索引编码,每个字符都对应一个索引,具体的关系图,如下:


这也是名称中64的由来。

编码方式

由于64等于2的6次方,所以一个Base64字符实际上代表着6个二进制位(bit)。
然而,二进制数据1个字节(byte)对应的是8比特(bit),因此,3字节(3 x 8 = 24比特)的字符串/二进制数据正好可以转换成4个Base64字符(4 x 6 = 24比特)。
为什么是3个字节一组呢? 因为6和8的最小公倍数是24,24比特正好是3个字节。

具体的编码方式:

  1. 将每3个字节作为一组,3个字节一共24个二进制位
  2. 将这24个二进制位分为4组,每个组有6个二进制位
  3. 在每组的6个二进制位前面补两个00,扩展成32个二进制位,即四个字节
  4. 每个字节对应的将是一个小于64的数字,即为字符编号
  5. 再根据字符索引关系表,每个字符编号对应一个字符,就得到了Base64编码字符


上图中的字符串 'you',经过转换后,得到的编码为: 'eW91'。

体积增大

我们可以看到,当3个字符进行Base64转换编码后,最后变成了4个字符。因为每个6比特位,都补了2个0,变成8比特位,对应1字节。
这里正好多了三分之一,所以正常情况下,Base64编码的数据体积通常比原数据的体积大三分之一
这也是为什么我们在前面讲使用Base64编码优化图片时,需要强调是小图标,如果图片都使用该方式,则静态文件会增大很多,并不合适。

= 等号

3个英文字符,正好能转成4个Base64字符。那如果字符长度不是3的倍数,那应该使用什么样的规则呢?
其实也简单,我们在实际使用Base编码时,常会发现有第65个字符的存在,那就是 '=' 符号,这个等于号就是针对这种特殊情况的一种处理方式。
对于不足3个字节的地方,实际都会在后面补0,直到有24个二进制位为止。
但要注意的是,在计算字节数时,会直接使用总长度除以3,如果余数为1则会直接在最后补一个=,如果余数为2则补两个=。
因此,转码后的字符串需要补的后缀等号,要么是1个,要么是2个,具体的可以见下图:


图中第二个,使用的是单独的字符 'd',是为了区分索引字符表里的索引0,这个时候,得到编码中,会存在一个索引0对应的A字符,而'='是直接补上2个。

非ASCII码字符

由于 Base64 仅可对 ASCII 字符进行编码,如果是中文字符等非ASCII码,就需要先将中文字符转换为ASCII字符后,再进行编码才行。

编解码方法

btoa 和 atob

JavaScript提供了两个原生方法,用来处理Base64编码:btoa() 和 atob()。

  • btoa(): 将字符串或二进制值转换成Base64编码字符串。
    注意:btoa方法只能直接处理ASCII码的字符,对于非ASCII码的字符,则会报错。
  • atob(): 对base64 编码的字符串进行解码。
    注意:atob方法如果传入字符串参数不是有效的Base64编码(如非ASCII码字符),或者其长度不是4的倍数,会报错。
btoa('you') // 'eW91'
atob('eW91') // 'you'
btoa('中') // Uncaught domException: The string to be encoded contains characters outside of the Latin1 range.
atob('y') // Uncaught DOMException: The string to be decoded is not correctly encoded.

处理中文字符

由于btoa、atob 仅支持对ASCII字符编码,也就是单字节字符,而我们平时的中文都是 2-4 字节的字符。
因此,可以先将中文字符转为 utf-8 的编码,将utf-8编码当做字符,这样就可以对多个单字节字符进行编码。

对于中文可以使用这两个方法: encodeURIComponent() 和 decodeURIComponent()。

  • encodeURIComponent():将非ACSII码的字符进行utf-8编码
  • decodeURIComponent():解码使用

如下,编解码中文的方式:

window.btoa(encodeURIComponent('中国'))
// 'JUU0JUI4JUFEJUU1JTlCJUJE'
decodeURIComponent(window.atob('JUU0JUI4JUFEJUU1JTlCJUJE'))
// '中国'

第三方库

  • js-base64

前端常见应用

接下来,我们了解下前端开发中常见的对Base64编码的一些使用场景。
Base64在前端方面的应用,多数都是针对图片的处理,一般都是基于DataURL的方式来使用。

Data URL 由 data:前缀、MIME类型(表明数据类型)、base64标志位(如果是文本,则可选)以及 数据本身 四部分组成。
具体的格式:data:[<mime type>][;base64],<data>。
这里的第四部分 <data> 数据本身,就是一个Base64字符串。

小图片转码

即开篇说的针对图片优化,使用Base64能减少请求数的,可以在img标签下,或者css中:

<img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0c......Ii8+PC9nPjwvc3ZnPg==">
.icon {
  background: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0c......Ii8+PC9nPjwvc3ZnPg==);
}

当我们使用vuereact框架时,也可以通过url-loader来配置,图标转Base64的大小:

  .loader('url-loader')
  .tap(options => {
    options.limit = 10240 // 10kb
    return options
  })

文件读取

Web环境下,有提供 FileReader 的api,用来读取文件的数据,可以通过它的 readAsDataURL() 方法,将文件数据读取为Base64编码的字符串数据:

  let reader = new FileReader()
  reader.onload = () => {
    let base64Img = reader.result
  };
  reader.readAsDataURL(file)

该方法常用在图片上传中。

Canvas生成图片

Canvas本质上是一个位图图像,它有提供 toDataURL() 方法,将画布导出生成为一张图片,该图片将以Base64编码的格式进行保存。

const dataUrl = canvasEl.toDataURL()
// data:image/png;base64,PHN2ZyB4bWxucz0iaHR0c......

其他

处理图片展示外,还会在特殊数据传输、简单编码和加密、代码混淆、部分证书中,见到Base64编码字符串。

总结

最后再来总结一下Base64的特点:

  • 将二进制数据转为字符串(ASCII码),方便数据传输。
  • 浏览器能直接展示Base64编码图片,减少请求。
  • 编码后数据会大至少三分之一,需要额外的方法处理编解码。

链接: https://fly63.com/article/detial/11725

几种常用的编码方式

最近在做加解密这块的开发,使用频率最高的就是 Nodejs 的 crypto 模块了,中间出现了很多种不同的编码方式。一直对这些编码方式处于熟练拼写的状态,但是到底有什么区别处于一知半解,借此机会正好整理下这之间的关系。

彻底理解编码

不管是爬虫获取的,浏览器收到的还是从本地硬盘读取的,都是二进制,选择正确的编码类型,才能把二进制或者说01序列解析为正确的字符。也就是用何种方式解析01数字

JavaScript中常见的5种不良编码习惯

在这篇文章中,我描述了JavaScript中常见的5种不良编码习惯。重要的是,本文会给出一些可行的建议,如何的摆脱摆脱这些习惯。

jquery选择图片url转base64编码

之前一次使用post请求上传图片过多,post请求理论上对参数的大小没有限制,但是服务器有限制,导致上传失败,这时设置一下Tomcat的server.xml里面的maxPostSize就可以了。不过还是建议使用Form表单提交文件

这6种编码方法,你掌握了几个?

Don Roberts 提出的一条重构准则:第一次做某件事时只管去做;第二次做类似的事时会产生反感,但无论如何还是可以去做;第三次再做类似的事时,你就应该重构

网页编码:UTF-8、GB2312

通过改变charset=utf-8中的utf-8就可以改变网页的编码。 一般我们在写CSS文件时候也需要在CSS文件顶部使用@charset utf-8;来定义此CSS文件编码类型。一般html源代码和css文件编码要统一,如果不统一会导致CSS hack

读懂Base64编码

我们知道一个字节可表示的范围是 0 ~ 255(十六进制:0x00 ~ 0xFF), 其中 ASCII 值的范围为 0 ~ 127(十六进制:0x00 ~ 0x7F);而超过 ASCII 范围的 128~255

Unicode 和 UTF-8 是什么关系?

十几年前,国内 UTF-8 还不太流行,新手开发过程中,乱码问题是很常见的。记得我刚毕业那会,公司的系统是这样的:数据库 MySQL 使用的是 Latin-1 编码(IOS8859-1)

Get 一种可以用来装逼的 JavaScript 编码风格

JavaScript 是弱类型的编程语言,我们在写代码的时候充斥着大量的类型转换,在我之前的文章 【JS进阶】你真的掌握变量和类型了吗 中有过相关的介绍,其实上面代码的核心就是用到了下面三个类型转换:

前端常见的字符编码方案

在前端开发中,最常见的字符编码方案是 UTF-8。UTF-8是一种可变长度的 Unicode 编码方案,可以表示几乎所有的字符,并且与 ASCII 兼容。由于互联网的广泛应用和多语言的支持

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!