Base64 图片数据转换上传

1. base64

1.1. 背景介绍

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

用记事本打开exe、jpg、pdf这些文件时,我们都会看到一大堆乱码,因为二进制文件包含很多无法显示和打印的字符,所以,如果要让记事本这样的文本处理软件能处理二进制数据,就需要一个二进制到字符串的转换方法。Base64 就是一种最常见的二进制编码方法。

简单的说,Base64 将 8 位的非英语字符转化为 7 位的 ASCII 字符。最初为了解决电子邮件中不能直接使用非 ASCII 码字符的问题而被提出,除此之外还有别的意义:

  • 所有的二进制文件,都可以因此转化为可打印的文本编码,使用文本软件进行编辑
  • 能够对文本进行简单的加密

1.2. 原理简析

Base64,就是说选出64个字符:

  • 小写字母 a-z
  • 大写字母 A-Z
  • 数字 0-9
  • 符号 “+”、”/“

实际上还有作为垫字的“=”,所以在一段 base64 文本中会看到 65 个字符。将除了ASCII字符以外的其他所有符号都转换成这个字符集中的字符。

Base64 对二进制数据进行处理,每 3 个字节一组,一共是 3 x 8 = 24bit,划为4组,每组正好 6 个 bit:

得到四个 6 位的数据之后给每一个开头加上 00,这样 3 个字节的数据就转成了 4 个字节。正是因此经过 Base64 编码过的数据会在大小上增加 33% 左右。

如果要编码的二进制数据不是 3 的倍数,实际编码可能会在最后剩下 1 个或 2 个字节,Base64用 \x00 字节在末尾补足后,再在编码的末尾加上 1 个或 2 个 = 号,表示补了多少字节,在解码的时候,会自动去掉。

2. 相关方法

2.1. window.atob()window.btoa()

在JavaScript中,有 2 个函数分别用来处理解码和编码 Base64 字符串:

  • window.atob():对用 Base64 编码过的字符串进行解码
  • window.btoa():从 String 对象中创建一个 Base64 编码的 ASCII 字符串,其中字符串中的每个字符都被视为一个二进制数据字节

2.2. Uint8Array

Uint8Array 数组类型表示一个 8 位无符号整型数组,创建时内容被初始化为 0。

创建完后,可以以对象的方式或使用数组下标索引的方式引用数组中的元素。

2.3. Blob

Blob 对象表示一个不可变、原始数据的类文件对象。Blob 表示的不一定是 JavaScript 原生格式的数据。File 接口基于Blob,继承了 blob 的功能并将其扩展使其支持用户系统上的文件。

要构建一个 Blob 对象可以使用 Blob() 构造函数:

1
const aBlob = new Blob( array, options );

Blob() 构造函数返回的 Blob 对象内容由参数数组中给出的值的串联组成。参数如下:

  • array 是一个由ArrayBuffer, ArrayBufferView, Blob, DOMString 等对象构成的 Array ,或者其他类似对象的混合体,它将会被放进 Blob。DOMStrings会被编码为UTF-8
  • options 是一个可选的 BlobPropertyBag 字典,它可能会指定如下两个属性:key 和 ending

3. 具体实现

为了将 Base64 数据转换成二进制的数据进行上传,可以分成以下几个步骤:

  1. 去掉 Base64 图片数据字串中开头一些类型说明的内容
  2. 取出 Base64 图片数据字串中的 MIME 说明
  3. window.atob() 解码 Base64 转换成图片原生的数据字串
  4. 将得到的图片原生字串放入 Uint8Array
  5. 转换成 Blob 格式
  6. 调用 FormData 的 append() 插入 Blob 数据,连同 form 中的数据一同发送
1
2
3
4
5
6
7
8
9
10
11
// 将base64转换成二进制图片(Blob)
function dataURItoBlob (base64Data) {
const byteString = window.atob(base64Data.split(',')[1]); // 去掉url的头,是一段类型说明
const mimeString = base64Data.split(',')[0].split(':')[1].split(';')[0]; // 取出 MIME类型

let ia = new Uint8Array(byteString.length); //
for (let i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
return new Blob([ia], { type: mimeString });
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import request from 'superagent';

function submit () {
const blob = dataURItoBlob(base64Data);
const fd = new FormData(document.querySelector('form'));
fd.append(fileName, blob, file.file.name);

request.post(action)
.send(fd)
.end(function(err, res) {
// eg.成功回调的处理逻辑
if (err || !res.ok) {
// 处理 request 返回的请求错误
console.log("not 200 error msg:" + err);
// ...
} else {
// 处理后端返回的请求错误
if (res.body.errorCode === 0) {
// do something ...
} else {
// do something ...
}
}
});
}

参考: