nodejs - base64 编码与解码 encode & decode

什么是Base64编码?

Base64 编码是一种将数据(通常是二进制)转换为 ASCII 字符集的方法。 在这里需要特别指出的是,Base64 不是一种加密或压缩技术,尽管有时由于它似乎隐藏数据的方式而将其与加密混淆。 事实上,Base64 编码信息的大小是原始数据实际大小的 1.3333 倍。

Base64 是使用最广泛的基本编码技术,Base16 和 Base32 是另外两种常用的编码方案。

Base64 是如何工作的?

将数据转换为 base64 是一个多步骤过程。 以下是它如何处理文本字符串:

1、计算输入文本的 8 位二进制版本
2、将 8 位版本的数据重新分组为多个 6 位的块
3、找到每个 6 位二进制块的十进制版本
4、通过 Base64 查找表找到每个十进制值的 Base64 符号

为了更好地理解这个概念,让我们看一个例子。

假设我们有字符串“Go win”,我们想将它转换成 Base64 字符串。 第一步是将这个字符串转换成二进制。 “Go win”的二进制版本是:

01000111  01101111  00100000  01110111  01101001  01101110
G         o                   w         i         n

你可以在这里看到每个字符由 8 位表示。 然而正如我们之前所说,Base64 将 8 位二进制形式的数据转换为 6 位的块。 这是因为Base64格式只有64个字符:26个大写字母,26个小写字母,10个数字字符,以及换行符“+”和“/”。

Base64 并不使用所有的 ASCII 特殊字符,而只使用这几个。 请注意,Base64 的某些实现使用与“+”和“/”不同的特殊字符。

回到示例,让我们将 8 位数据分解为 6 位数据块。

010001  110110  111100  100000  011101  110110  100101  101110

您不会总是能够将数据分成完整的 6 位集合,在这种情况下,您将不得不处理填充。

现在对于上面的每个块,我们必须找到它的十进制值。 这些十进制值已在下面给出:

二进制  十进制
010001  17
110110  54
111100  60
100000  32
011101  29
110110  54
100101  37
101110  46

最后,我们必须查看我们刚刚从二进制数据计算出的每个小数的 Base64 值。 Base64编码表如下:

这里可以看到十进制的17对应“R”,十进制的54对应“2”,以此类推。 使用此编码表我们可以看到字符串“Go win”使用 Base64 编码为“R28gd2lu”。 您可以使用任何在线文本到 Base64 转换器来验证此结果。

为什么要使用Base64编码?

以二进制格式发送信息有时会有风险,因为并非所有应用程序或网络系统都可以处理原始二进制文件。 另一方面,ASCII 字符集广为人知,对于大多数系统来说处理起来非常简单。

例如,电子邮件服务器需要文本数据,因此通常使用 ASCII。 因此,如果您想将图像或任何其他二进制文件发送到电子邮件服务器,您首先需要将其编码为基于文本的格式,最好是 ASCII。 这就是 Base64 编码在将二进制数据转换为正确格式时非常方便的地方。

使用 Node.js 编码 Base64 字符串

在 Node.js 中编码 Base64 字符串的最简单方法是通过 Buffer 对象。 在 Node.js 中,Buffer 是一个全局对象,这意味着您不需要使用 require 语句来在您的应用程序中使用 Buffer 对象。

在内部 Buffer 是一个不可变的整数数组,它也能够执行许多不同的编码/解码。 这些包括到/从 UTF-8、UCS2、Base64 甚至十六进制编码。 当您编写处理和操作数据的代码时,您可能会在某些时候使用 Buffer 对象。

看看下面的例子。 在这里,我们将使用 Buffer 对象将文本字符串编码为 Base64。 将以下代码保存在文件“encode-text.js”中


'use strict';

let data = 'stackabuse.com';
let buff = Buffer.from(data);
let base64data = buff.toString('base64');

console.log('"' + data + '" converted to Base64 is "' + base64data + '"');

在上面的脚本中,我们创建了一个新的缓冲区对象并将我们要转换为 Base64 的字符串传递给它。 然后,我们在刚刚创建的缓冲区对象上调用“toString”方法,并将“base64”作为参数传递给它。 以“base64”为参数的“toString”方法将以Base64 字符串的形式返回数据。 运行上面的代码,您将看到以下输出。

$ node encode-text.js
"stackabuse.com" converted to Base64 is "c3RhY2thYnVzZS5jb20="

在输出中,我们可以看到我们转换为 Base64 的字符串对应的 Base64。

使用 Node.js 解码 Base64 字符串

解码 Base64 字符串与编码它非常相似。 您必须创建一个新的缓冲区对象并将两个参数传递给它的构造函数。 第一个参数是 Base64 格式的数据,第二个参数是“base64”。 然后您只需在缓冲区对象上调用“toString”,但这次传递给该方法的参数将是“ascii”,因为这是您希望 Base64 数据转换成的数据类型。 请查看以下代码片段以供参考。

'use strict';

let data = 'c3RhY2thYnVzZS5jb20=';
let buff = Buffer.from(data, 'base64');
let text = buff.toString('ascii');

console.log('"' + data + '" converted from Base64 to ASCII is "' + text + '"');

将数据添加到“ascii.js”文件并保存。 这里我们使用“Tm8gdG8gUmFjaXNt”作为 Base64 输入数据。 当这个数据被解码时,它应该显示“No to Racism”。 这是因为从上一个例子我们知道“No to Racism”等于“Tm8gdG8gUmFjaXNt”。 使用 Node.js 运行以上代码。 它将显示以下输出。

将二进制数据编码为 Base64 字符串

正如文章开头所述,Base64编码的主要目的是将二进制数据转换为文本格式。 让我们看一个示例,我们将图像(二进制数据)转换为 Base64 字符串。 看看下面的例子。

'use strict';

const fs = require('fs');

let buff = fs.readFileSync('stack-abuse-logo.png');
let base64data = buff.toString('base64');

console.log('Image converted to base 64 is:\n\n' + base64data);

在上面的代码中,我们通过 fs 模块的 readFileSync() 方法将图像加载到缓冲区中。 其余过程类似于从普通 ASCII 字符串创建 Base64 字符串。

当您运行上面的代码时,您将看到以下输出。

$ node encode-image.js
Image converted to Base64 is:

iVBORw0KGgoAAAANSUhEUgAAABkAAAATCAYAAABlcqYFAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAACXBIWXMAAAsTAAALEwEAmpwYAAABWWlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iWE1QIENvcmUgNS40LjAiPgogICA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPgogICAgICA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIgogICAgICAgICAgICB4bWxuczp0aWZmPSJodHRwOi8vbnMuYWRvYmUuY29tL3RpZmYvMS4wLyI+CiAgICAgICAgIDx0aWZmOk9yaWVudGF0aW9uPjE8L3RpZmY6T3JpZW50YXRpb24+CiAgICAgIDwvcmRmOkRlc2NyaXB0aW9uPgogICA8L3JkZjpSREY+CjwveDp4bXBtZXRhPgpMwidZAAADuUlEQVQ4EbVUTUtcZxR+7ufkXp1SZ4iZRE1EDVQRnTAhowsZMFm40I2rNqUIIev8hvoPQroQXBTqwiAWcd0EglEhiZNajVZrQGXAWAzaZpzMnZn7lXPeeIe5DaWb9Ax33vOec8/znI/3vVI6nfbxP4v8b/iSJIGfzyGfkPi+D13XUalUBL6qqmIvy5+8WuX/r2RCkUzAoIuLi2hqaoLrutjb28P6+josyxJkiqJA07SQXiqVwHaOZYx/itLc3Px9YIxEIlheXsbExATGxsYwMjIiwEdHRwXA/Pw8EokEcrkcDg4OYJomVlZWMDU1JSqfmZlBR0cHbNsOtVoNCHjlTFiSySQMwxAVxONxQbi0tIRMJoPe3l5MT0+jtbUVg4ODYGImY18qlcL4+DhisZjoggCjv1C7uOyenh7Mzs5iY2ND6FQpdnd3sba2JloSjUYxPDyM/v5+TE5OYn9/X9jZtrOzg+3t7WqyAUmoEu419/+HBw9E+eVymbJqAJP39fWBCR3HEU+hUMDQ0JCYGc8um81iYGAAjY2N8DwvwBdraCY8tHhDA1Y3N9Hd3S2yvH37O7RcbsF7AuUsD9+8wdOFBTx/8QJtbW1C5/nMzc3R0D2UyxXk83lRXcAk1V5GCT5sSUGDbeHxy9/EO98M9OOXzT9wfHISxKC1vR0GHfOtrS2g/SouWwU0Xkggu7qO9PUkJFULnbIQyTm6ewu2hF+vnOIIUQwdGlg8f4QF6wvMWBq+pAkaskSnx4FFVUf0CNpcC797KizXQ4oAHhVdXJJ81F7j6kwUynPHlXDPdFB2fRj+KVK0KvT2rbp3uKYryJU11Cke8qqMuOoioeeJ1MPDYxM36m1cNSq4GdFx58RAWvbx8TrXnK4IgR16Em5GK4iqHi5GHHxLgcSDn97WgZPoND+GGZRpPYH85cgiiRQl1ltXxmFFQ5PuopP8TrW5ZyRcWp7AbmkeZefg5+N6PPnbRJdpw/YlfB0vQiPQZwVdZNtFZEVK6D1VTnccJlXzuqTjvOZiq6Rhj2KqLSJsofOHgIl8+t0/qsfDioxmSUWGjrRFzhYi/5Oynrdl3KXHIZDXtF6hil8R6I9FBV/RvDLnXKxSbAdVYhNeINXBMwmXWCTQGG2Y+Jj+dFrfEmiMAtmeowpo9ojTvkD+A/L1UJUMmiVfkuz6WTyZhFRJAgP33j3bsM5k/Fng68UP21hYJyyxZwLWuS2cKMfUSm3rhD0g4E2g197fwMZ+Bgt8rNe2iP2BhL5dgfFzrx8AfECEDdx45a0AAAAASUVORK5CYII=

尽管实际图像非常小 (25x19),但输出仍然相当大,部分原因是 Base64 增加了数据的大小,正如我们之前提到的。

将 Base64 字符串解码为二进制数据

正如我们在前面的部分中看到的,这里的逆向过程与我们解码 Base64 字符串的方式非常相似。 最大的区别在于输出目的地以及数据在那里的写入方式。 让我们看看这个例子:

'use strict';

const fs = require('fs');

let data = `iVBORw0KGgoAAAANSUhEUgAAABkAAAATCAYAAABlcqYFAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAACXBIWXMAAAsTAAALEwEAmpwYAAABWWlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iWE1QIENvcmUgNS40LjAiPgogICA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPgogICAgICA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIgogICAgICAgICAgICB4bWxuczp0aWZmPSJodHRwOi8vbnMuYWRvYmUuY29tL3RpZmYvMS4wLyI+CiAgICAgICAgIDx0aWZmOk9yaWVudGF0aW9uPjE8L3RpZmY6T3JpZW50YXRpb24+CiAgICAgIDwvcmRmOkRlc2NyaXB0aW9uPgogICA8L3JkZjpSREY+CjwveDp4bXBtZXRhPgpMwidZAAADuUlEQVQ4EbVUTUtcZxR+7ufkXp1SZ4iZRE1EDVQRnTAhowsZMFm40I2rNqUIIev8hvoPQroQXBTqwiAWcd0EglEhiZNajVZrQGXAWAzaZpzMnZn7lXPeeIe5DaWb9Ax33vOec8/znI/3vVI6nfbxP4v8b/iSJIGfzyGfkPi+D13XUalUBL6qqmIvy5+8WuX/r2RCkUzAoIuLi2hqaoLrutjb28P6+josyxJkiqJA07SQXiqVwHaOZYx/itLc3Px9YIxEIlheXsbExATGxsYwMjIiwEdHRwXA/Pw8EokEcrkcDg4OYJomVlZWMDU1JSqfmZlBR0cHbNsOtVoNCHjlTFiSySQMwxAVxONxQbi0tIRMJoPe3l5MT0+jtbUVg4ODYGImY18qlcL4+DhisZjoggCjv1C7uOyenh7Mzs5iY2ND6FQpdnd3sba2JloSjUYxPDyM/v5+TE5OYn9/X9jZtrOzg+3t7WqyAUmoEu419/+HBw9E+eVymbJqAJP39fWBCR3HEU+hUMDQ0JCYGc8um81iYGAAjY2N8DwvwBdraCY8tHhDA1Y3N9Hd3S2yvH37O7RcbsF7AuUsD9+8wdOFBTx/8QJtbW1C5/nMzc3R0D2UyxXk83lRXcAk1V5GCT5sSUGDbeHxy9/EO98M9OOXzT9wfHISxKC1vR0GHfOtrS2g/SouWwU0Xkggu7qO9PUkJFULnbIQyTm6ewu2hF+vnOIIUQwdGlg8f4QF6wvMWBq+pAkaskSnx4FFVUf0CNpcC797KizXQ4oAHhVdXJJ81F7j6kwUynPHlXDPdFB2fRj+KVK0KvT2rbp3uKYryJU11Cke8qqMuOoioeeJ1MPDYxM36m1cNSq4GdFx58RAWvbx8TrXnK4IgR16Em5GK4iqHi5GHHxLgcSDn97WgZPoND+GGZRpPYH85cgiiRQl1ltXxmFFQ5PuopP8TrW5ZyRcWp7AbmkeZefg5+N6PPnbRJdpw/YlfB0vQiPQZwVdZNtFZEVK6D1VTnccJlXzuqTjvOZiq6Rhj2KqLSJsofOHgIl8+t0/qsfDioxmSUWGjrRFzhYi/5Oynrdl3KXHIZDXtF6hil8R6I9FBV/RvDLnXKxSbAdVYhNeINXBMwmXWCTQGG2Y+Jj+dFrfEmiMAtmeowpo9ojTvkD+A/L1UJUMmiVfkuz6WTyZhFRJAgP33j3bsM5k/Fng68UP21hYJyyxZwLWuS2cKMfUSm3rhD0g4E2g197fwMZ+Bgt8rNe2iP2BhL5dgfFzrx8AfECEDdx45a0AAAAASUVORK5CYII=`;

let buff = Buffer.from(data, 'base64');
fs.writeFileSync('stack-abuse-logo-out.png', buff);

console.log('Base64 image data converted to file: stack-abuse-logo-out.png');

在这里您可以看到我们从 Base64 数据开始(也可以从套接字或其他通信线路接收)并将其加载到 Buffer 对象中。 创建缓冲区时,我们告诉它它是 base64 格式,这允许缓冲区相应地解析它以进行内部存储。

要以原始 PNG 格式保存数据,我们只需将 Buffer 对象传递给我们的 fs.writeFileSync() 方法,它会为我们进行转换。

小结

Base64 编码是将二进制数据转换为纯 ASCII 文本的最常用方法之一。 对于无法轻松处理二进制数据(如 HTML 标记或 Web 请求中的图像)的一个或多个系统之间的通信,它是一种非常有用的格式。

在 Node.js 中,Buffer 对象可用于将 Base64 字符串与许多其他格式进行编码和解码,使您可以根据需要轻松地来回转换数据。

posted @ 2023-03-14 17:56  炎黄子孙,龙的传人  阅读(5031)  评论(0编辑  收藏  举报