一文讲清base64编码原理

目录
  • 前言
  • base64 由来
  • base64 的编码原理
  • base64 编码对照表
  • base64 的编码转换规则
  • base64 优缺点
  • JavaScript 的 base64 转码方法
    • Web API 二进制与 base64 转换
    • base64 转二进制
    • base64 转成 Blob
  • 相关文献

前言

平静之下,蓦然回首,base64 却在灯火阑珊处。

今天翻开旧项目发现挺多图片相关的插件都是用 base64 来显示图片的。谈到 base64,脑海遐想翩翩,思绪回荡之下 base64 瑕瑜互见。本文旨在记录工作中遇见的问题并加以总结,如有不妥请指正~

base64 由来

base64 是网络传输 8Bit 字节代码的编码方式之一,是一种基于 64 个可打印字符来表示二进制数据的方法。在做支付系统时,报文交互都需要使用 base64 对明文进行转码,然后再进行签名或加密,之后再进行(或再次 base64 转码)传输。那么,base64 到底起到什么作用呢?

在参数传输的过程中经常遇到的一种情况:使用全英文的字符串没问题,但一旦涉及到中文就会出现乱码的情况。与此类似,网络上传输的字符并不全是可打印的字符,比如二进制文件、图片等。base64 的出现就是为了解决此问题,它是基于 64 个可打印的字符来表示二进制的数据的一种方法。

电子邮件刚问世的时候,只能传输英文,但后来随着用户的增加,中文、日韩俄文等文字的用户也有需求,但这些字符并不能被服务器或网关有效处理,因此 base64 就登场了。随后,base64 在 URL、Cookie、网页传输少量二进制文件中也有相应的使用。

base64 的编码原理

基于a-zA-Z0-9+/这 64 个字符来标识二进制数据,另外=符号用于当字节缺位时补用。

base64 编码对照表

base64 编码对照表


索引


对应字符


索引


对应字符


索引


对应字符


索引


对应字符


0


A


17


R


34


i


51


z


1


B


18


S


35


j


52


0


2


C


19


T


36


k


53


1


3


D


20


U


37


l


54


2


4


E


21


V


38


m


55


3


5


F


22


W


39


n


56


4


6


G


23


X


40


o


57


5


7


H


24


Y


41


p


58


6


8


I


25


Z


42


q


59


7


9


J


26


a


43


r


60


8


10


K


27


b


44


s


61


9


11


L


28


c


45


t


62


+


12


M


29


d


46


u


63


/


13


N


30


e


47


v


14


O


31


f


48


w


15


P


32


g


49


x


16


Q


33


h


50


y

base64 的编码转换规则

base64 要求把每三个 8Bit 的字节转换四个 6Bit 的字节(3*8 = 4*6 = 24),然后把 6Bit再添两位高位 0,组成四个 8Bit 的字节(4*8=32)。

为什么使用 3 个字节一组呢?因为 6 和 8 的最小公倍数为 24,三个字节正好 24 个二进制位,每 6 个 bit 位一组,恰好能够分为 4 组。

同时用于分组后每组添加两个高位 0,转换后的字符串理论上将要比原来的字符长 1/3(24/32=1/3)

  • 步骤分解:

    将待转换的字符串每三个字符分为一组,每个字符字节占 8bit,那么共有 24 个二进制位。

    将 24 个二进制位每 6 个字节为一组,共分为 4 组。

    在每组 6 字节前面添加两个 0,每组由 6 字节变为 8 字节二进制位,组成总共 32 个二进制位,即四个字节。

    根据 base64 编码对照表获得对应的值。

  • 举个栗子
    • 以标准 3 个字符LJY为例。

    LJY 对应的 ASCII 码值分别为 76、74、89,对应的二进制值是 01001100、01001010、01011001。由此组成一个 24 位的二进制位字符串。

    将 24 位的二进制位字符串,按照每 6 位二进制位一组分成 4 组。

    对 4 组 每组 6 位二进制位字符串前面补两个 0,每组扩展为 8 位二进制位,4 组共扩展成 32 个二进制位,此时 4 组二进制位分别为:00010011、00000100、00101001、00011001。其对应的 base64 编码索引为:19、4、41、25。

    用 base64 编码索引值在 base64 编码表中进行查找,分别对应:T、E、p、Z。

    • 因此LJYbase64 编码之后就变为:TEpZ。
|   文本           |    L     |    J     |    Y     |
|  ASCII          |    76    |    74    |    89    |
| 二进制位         | 01001100 | 01001010 | 01011001 |
| 分组二进制       | 010011   | 000100   | 101001   | 011001   |
| 分组二进制补2个0 | 00010011 | 00000100 | 00101001 | 00011001 |
| 分组索引         |   19     |   4      |   41     |   25     |
| base64编码       |   T     |   E      |    p      |   Z      |

主要展示:
转换前二进制位: 01001100 01001010 01011001
转换后二进制位: 00010011 00000100 00101001 00011001
复制代码
  • 字符位数不足情况

上述栗子是面向刚好三个字符为一组的情况。当然不是所有时候都这么巧字符位数足够,除此以外有位数不足的情况。那么,面对字符位数不足的情况下该如何处理呢?

base64 给出的方案是,当每组字符不足三位时,不足位数位置需要使用=符号补上。

位数不足情况处理情景:

  • 位数缺一个字节:一个字节共 8 个二进制位,依旧按照规则进行分组。此时共 8 个二进制位,每 6 个一组,则第二组缺少 4 位,用 0 补齐,得到两个 base64 编码,而后面两组没有对应数据,都用=补上。
  • 位数缺两个字节:两个字节共 16 个二进制位,依旧按照规则进行分组。此时总共 16 个二进制位,每 6 个一组,则第三组缺少 2 位,用 0 补齐,得到三个 base64 编码,第四组完全没有数据则用=补上。

位数不足图解如下:

<!-- 缺2位字符,字符串以A为例转换base64后位QQ== -->
|   文本(1Byte)  |    A     |          |          |
| 二进制位         | 01000001 |          |          |
| 分组二进制       | 010000   | 010000   |          |          |
| 分组二进制补0    | 00010000 | 00010000 |          |          |
| 分组索引         |   16     |   16     |          |          |
| base64编码       |   Q     |   Q      |    =      |   =      |

<!-- 缺1位字符,字符串以AB为例转换base64后位QUI= -->
|   文本(1Byte)  |    A     |     B    |          |
| 二进制位         | 01000001 | 01000010 |          |
| 分组二进制       | 010000   | 010100   |  001000  |          |
| 分组二进制补0    | 00010000 | 00010100 | 00001000 |          |
| 分组索引         |   16     |   20     |    8      |          |
| base64编码       |   Q     |   U      |    I      |   =      |
复制代码

列举了一个字符到三个字符转换为 base64 ,可以发现将 base64 就是按照 base64 编码对照表来将二进制转换为字符串,使得数据不能直接明文展示出来,但也算不上是加密,而这巧好可用在传输、存储、表示二进制领域的情景。

  • 另外值得注意的是,不用语言如中文有多种编码(比如:utf-8、gb2312、gbk 等),不同编码对应 base64 编码结果都不一样。
  • 其次在推演过程中可发现 base64 即用 6 位字节(2 的 6 次幂就是 64)表示字符同理,Base32 就是用 5 位字节,Base16 就是用 4 位字节。大家可以按照上面的步骤进行演化测试。

base64 优缺点

知道 base64 是什么后,也该到为什么出现了。为什么要是使用 base64 呢,这要从其优缺点入手来选择适合场景了。

  • 优势:

    • base64 适合不同平台、不同语言的传输;
    • 页面中内嵌使用 base64 格式的小图片,可减少了服务器访问次数;
    • 二进制位转换 base64 算法简单,对性能影响不大;
  • 缺点
    • 二进制文件转换为 base64 后,体积大概增加 1/3;

      • 在基于 Android6.0 及以下默认浏览器实测场景中发现,某些机型如中兴上传 base64 图片会因为字符大小过大导致上传奔溃的情况。
      • 字符长度过大的 base64 不适应使用在 URL 情景,因为 IOS 端浏览器会限制 URL 长度,当长度超过时会自动切除多余部分,导致数据丢失。
      • base64 字符过大会导致页面加载速度变慢,因此建议 10kb 以下的图片使用。
    • base64 无法缓存,要缓存只能缓存包含 base64 的文件,比如 js 或者 css;
    • 面对大文件时,会消耗一定的 CPU 进行编解码

JavaScript 的 base64 转码方法

Web API 二进制与 base64 转换

  • atob(encodedData) : 解码一个 base64 编码的字符串。

enCodedData,是一个通过 btoa() 方法编码的字符串, 为二进制字符串包含 base64 编码的数据。并返回包含来自 encodedData 的解码数据的 ASCII 字符串。

  • btoa(stringToEncode) : 创建一个 bas64 编码的字符串。

stringToEncode 为要编码的二进制字符串。并返回包含 stringToEncode 的 base64 表示形式的 ASCII 字符串。

另外在 JavaScript 中,字符串使用 UTF-16 字符编码表示:在这种编码中,字符串表示为 16 位(2 字节)单元的序列。每个 ASCII 字符都可以放入其中一个单元的第一个字节,但许多其他字符不能。

base64 在设计上需要二进制数据作为其输入。就 JavaScript 字符串而言,这意味着每个字符只占用一个字节的字符串。因此,如果将一个字符串传递到 btoa()中,其中包含占用多个字节的字符,则会出现错误,因为这不被视为二进制数据,因此超 16 位字符在使用 btoa()时需要先对字符转码为二进制位。

// 简单数据
const encodedData = btoa('Hello, world'); // encode a string
const decodedData = atob(encodedData); // decode the string

/* 复杂数据 */
// convert a Unicode string to a string in which
// each 16-bit unit occupies only one byte
function toBinary(string) {
  const codeUnits = new Uint16Array(string.length);
  for (let i = 0; i < codeUnits.length; i++) {
    codeUnits[i] = string.charCodeAt(i);
  }
  const charCodes = new Uint8Array(codeUnits.buffer);
  let result = '';
  for (let i = 0; i < charCodes.byteLength; i++) {
    result += String.fromCharCode(charCodes[i]);
  }
  return result;
}
function fromBinary(binary) {
  const bytes = new Uint8Array(binary.length);
  for (let i = 0; i < bytes.length; i++) {
    bytes[i] = binary.charCodeAt(i);
  }
  const charCodes = new Uint16Array(bytes.buffer);
  let result = '';
  for (let i = 0; i < charCodes.length; i++) {
    result += String.fromCharCode(charCodes[i]);
  }
  return result;
}

// a string that contains characters occupying > 1 byte
const myString = '☸☹☻☼☾☿';

const converted = toBinary(myString);
const encoded = btoa(converted);
console.log(encoded); // OCY5JjomOyY8Jj4mPyY=

const decoded = atob(encoded);
const original = fromBinary(decoded);
console.log(original); // ☸☹☻☼☾☿
  • 兼容性:atob() 方法不支持 IE9 及更早的 IE 版本。

base64 转二进制

// base64编码表
const map = {
  0: 52,
  1: 53,
  2: 54,
  3: 55,
  4: 56,
  5: 57,
  6: 58,
  7: 59,
  8: 60,
  9: 61,
  A: 0,
  B: 1,
  C: 2,
  D: 3,
  E: 4,
  F: 5,
  G: 6,
  H: 7,
  I: 8,
  J: 9,
  K: 10,
  L: 11,
  M: 12,
  N: 13,
  O: 14,
  P: 15,
  Q: 16,
  R: 17,
  S: 18,
  T: 19,
  U: 20,
  V: 21,
  W: 22,
  X: 23,
  Y: 24,
  Z: 25,
  a: 26,
  b: 27,
  c: 28,
  d: 29,
  e: 30,
  f: 31,
  g: 32,
  h: 33,
  i: 34,
  j: 35,
  k: 36,
  l: 37,
  m: 38,
  n: 39,
  o: 40,
  p: 41,
  q: 42,
  r: 43,
  s: 44,
  t: 45,
  u: 46,
  v: 47,
  w: 48,
  x: 49,
  y: 50,
  z: 51,
  '+': 62,
  '/': 63,
};

function base64to2(base64) {
  let len = base64.length * 0.75; // 转换为int8array所需长度
  base64 = base64.replace(/=*$/, ''); // 去掉=号(占位的)

  const int8 = new Int8Array(len); //设置int8array视图
  let arr1,
    arr2,
    arr3,
    arr4,
    p = 0;

  for (let i = 0; i < base64.length; i += 4) {
    arr1 = map[base64[i]]; // 每次循环 都将base644个字节转换为3个int8array直接
    arr2 = map[base64[i + 1]];
    arr3 = map[base64[i + 2]];
    arr4 = map[base64[i + 3]];
    // 假设数据arr 数据 00101011 00101111 00110011 00110001
    int8[p++] = (arr1 << 2) | (arr2 >> 4);
    // 上面的操作 arr1向左边移动2位 变为10101100
    // arr2 向右移动4位:00000010
    // | 为'与'操作: 10101110
    int8[p++] = (arr2 << 4) | (arr3 >> 2);
    int8[p++] = (arr3 << 6) | arr4;
  }
  return int8;
}

base64 转成 Blob

// base64图片转blob
function base64toBlob(base64) {
  var arr = base64.split(','),
    mime = arr[0].match(/:(.*?);/)[1] || 'image/png',
    bstr = atob(arr[1]), // 将base64转为Unicode规则编码
    n = bstr.length,
    u8arr = new Uint8Array(n);
  while (n--) {
    u8arr[n] = bstr.charCodeAt(n); // 转换编码后才可以使用charCodeAt 找到Unicode编码
  }
  return new Blob([u8arr], { type: mime });
}

/* 优化版 */
function base64ToBlob(base64) {
  var arr = base64.split(',');
  var mime = arr[0].match(/:(.*?);/)[1] || 'image/png';
  // 去掉url的头,并转化为byte
  var bytes = window.atob(arr[1]);
  // 处理异常,将ascii码小于0的转换为大于0
  var ab = new ArrayBuffer(bytes.length);
  // 生成视图(直接针对内存):8位无符号整数,长度1个字节
  var u8arr = new Uint8Array(ab);

  for (var i = 0; i < bytes.length; i++) {
    u8arr[i] = bytes.charCodeAt(i);
  }

  return new Blob([u8arr], { type: mime });
}

相关文献

到此这篇关于一文讲清base64编码原理的文章就介绍到这了,更多相关base64编码内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • js获取图片的base64编码并压缩

    获取图片的base64编码 <!DOCTYPE html> <html> <head> <meta charset="gbk"> <title></title> </head> <body> <input accept="image/*" name="upimage" id="upload_file" type="f

  • 深入浅出JavaScript中base64编码原理

    目录 前言 base64 由来 base64 的编码原理 base64 编码对照表 base64 的编码转换规则 base64 优缺点 JavaScript 的 base64 转码方法 Web API 二进制与 base64 转换 base64 转二进制 base64 转成 Blob 前言 平静之下,蓦然回首,base64 却在灯火阑珊处. 今天翻开旧项目发现挺多图片相关的插件都是用 base64 来显示图片的.谈到 base64,脑海遐想翩翩,思绪回荡之下 base64 瑕瑜互见.本文旨在记录

  • Base64编码的深入认识与理解

    Base64编码的深入认识与理解 之前在很多业务中都有见过或者用到过Base64编码,但一直一知半解,没有对它有一个深入的认识和理解.今天就来聊一聊Base64编码的问题. 首先要明确的是,Base64是一种可逆的编码方式,提到编码方式,我们首先想到的肯定是Ascii.GBK.Unicode这些常用的编码方法,那么Base64与这些编码方式有什么不同呢? 简单来将,Base64就是一种用64个Ascii字符来表示任意二进制数据的方法.主要用于将不可打印的字符转换成可打印字符,或者简单的说将二进制

  • 深入理解JavaScript中的Base64编码字符串

    目录 初步认识 Base64是怎么诞生的 基础定义 编码方式 体积增大 = 等号 非ASCII码字符 编解码方法 btoa 和 atob 第三方库 前端常见应用 小图片转码 文件读取 Canvas生成图片 其他 总结 在我们进行前端开发时,针对项目优化,常会提到一条:针对较小图片,合理使用Base64字符串替换内嵌,可以减少页面http请求. 并且还会特别强调下,必须是小图片,大小不要超过多少KB,等等. 那么,Base64又到底是什么呢? 初步认识 下面的这段字符串,应该是大家都很常见的. 通

  • Base64 编码介绍、Base64编码转换原理与算法

    Base64编码,是我们程序开发中经常使用到的编码方法.它是一种基于用64个可打印字符来表示二进制数据的表示方法.它通常用作存储.传输一些二进制数据编码方法!也是MIME(多用途互联网邮件扩展,主要用作电子邮件标准)中一种可打印字符表示二进制数据的常见编码方法!它其实只是定义用可打印字符传输内容一种方法,并不会产生新的字符集!有时候,我们学习转换的思路后,我们其实也可以结合自己的实际需要,构造一些自己接口定义编码方式.好了,我们一起看看,它的转换思路吧! Base64实现转换原理 它是用64个可

  • 一文讲清base64编码原理

    目录 前言 base64 由来 base64 的编码原理 base64 编码对照表 base64 的编码转换规则 base64 优缺点 JavaScript 的 base64 转码方法 Web API 二进制与 base64 转换 base64 转二进制 base64 转成 Blob 相关文献 前言 平静之下,蓦然回首,base64 却在灯火阑珊处. 今天翻开旧项目发现挺多图片相关的插件都是用 base64 来显示图片的.谈到 base64,脑海遐想翩翩,思绪回荡之下 base64 瑕瑜互见.本

  • java中Base64编码原理实例讲解

    什么是 Base64 编码 Base64 编码是最常见的编码方式,基于 64 个可打印字符来表示任意二进制数据的方法,是从二进制转换到可见字符的过程. 使用场景 数据加密或签名通过 Base64 转换为字符串存储或传输. 不能传输文件的网络环境可以转换 Base64 进行网络传输. 在文本资源(如 HTML 和 CSS文件)中嵌入图片文件或其他二进制资源. 在 URL.网页中传输少量二进制数据等等. Base64 编码原理 原理是把每 3 个字节(每个字节为 8 位, 3 个字节为 24 位)重

  • Go语言中的Base64编码原理介绍以及使用

    目录 前言 Go Base64编码 什么是Base64编码 为什么需要Base64编码 Base64编码原理 编码步骤 位数不足情况 Base64解码原理 Base64标准编码变种 总结 前言 在网络中传递参数时,我们经常会对参数进行Base64编码,那么Go 语言中如何进行Base64编码呢?Base64编码的原理是怎样的呢?通过这篇文章一起来了解下吧! Go Base64编码 标准Base64编码 // 标准Base64编码     src := "hello world"   

  • 关于base64编码的原理及实现方法分享

    一.Base64编码原理 步骤1:将所有字符转化为ASCII码:步骤2:将ASCII码转化为8位二进制:步骤3:将二进制3个归成一组(不足3个在后边补0)共24位,再拆分成4组,每组6位:步骤4:统一在6位二进制前补两个0凑足8位:步骤5:将补0后的二进制转为十进制:步骤6:从Base64编码表获取十进制对应的Base64编码: 说明:不足3个补0的最终Base64编码为=,而不是A! 二.Base64编码示例 示例一:zyq对应Base64编码为enlx 示例二:mzwu对应Base64编码为

  • Base64编码解码原理及C#编程实例

    一. Base64编码由来 为什么会有Base64编码呢?因为有些网络传送渠道并不支持所有的字节,例如传统的邮件只支持可见字符的传送,像ASCII码的控制字符就不能通过邮件传送.这样用途就受到了很大的限制,比如图片二进制流的每个字节不可能全部是可见字符,所以就传送不了.最好的方法就是在不改变传统协议的情况下,做一种扩展方案来支持二进制文件的传送.把不可打印的字符也能用可打印字符来表示,问题就解决了.Base64编码应运而生,Base64就是一种基于64个可打印字符来表示二进制数据的表示方法. 二

  • node.js学习之base64编码解码

    一. Base64编码由来 为什么会有Base64编码呢?因为有些网络传送渠道并不支持所有的字节,例如传统的邮件只支持可见字符的传送,像ASCII码的控制字符就 不能通过邮件传送.这样用途就受到了很大的限制,比如图片二进制流的每个字节不可能全部是可见字符,所以就传送不了.最好的方法就是在不改变传统协议的情 况下,做一种扩展方案来支持二进制文件的传送.把不可打印的字符也能用可打印字符来表示,问题就解决了.Base64编码应运而生,Base64就是一种 基于64个可打印字符来表示二进制数据的表示方法

  • Python将内容进行base64编码与解码实现

    目录 一.需求说明 二.base64简介 三.base64编码解码 3.1.Python中base64编码解码 3.2.Python使用示例 一.需求说明 需要使用Python实现将内容转为base64编码,解码,方便后续的数据操作. 二.base64简介 Base64是一种二进制到文本的编码方式[是一种基于 64 个可打印字符来表示二进制数据的表示方法(由于 2^6=64,所以每 6 个比特为一个单元,对应某个可打印字符.3 个字节有 24 个比特(3*8),对应于 4 个 Base64 单元

  • C#解码base64编码二进制数据的方法

    本文实例讲述了C#解码base64编码二进制数据的方法.分享给大家供大家参考.具体如下: 通过在Convert类的静态方法Convert.FromBase64String,可以讲base64编码的字符串解码为等效的byte []数组. using System; static class MyModClass { public static byte[] Base64DecodeString(this string inputStr) { byte[] decodedByteArray = Co

随机推荐