为啥“仅”使用 Base64 来编码二进制数据?

Posted

技术标签:

【中文标题】为啥“仅”使用 Base64 来编码二进制数据?【英文标题】:Why Base64 is used "only" to encode binary data?为什么“仅”使用 Base64 来编码二进制数据? 【发布时间】:2021-12-03 10:30:16 【问题描述】:

我在当今的互联网上看到了许多关于 base64 用法的资源。据我了解,所有这些资源似乎都以不同的方式说明了单个用例:在 Base64 中编码 binary 数据,以避免在 transit 期间将其误解/损坏为其他内容(通过中间系统)。但我没有发现任何解释以下内容:

    为什么二进制数据会被中间系统破坏?如果我将图像从服务器发送到客户端,任何中间服务器/系统/路由器将简单地将数据转发到客户端路径中的下一个适当的服务器/系统/路由器。为什么中间服务器/系统/路由器需要解释它接收到的东西?在当今的互联网上,有任何此类系统可能会损坏/错误解释其接收到的数据的示例吗? 为什么我们只担心二进制数据被破坏。我们使用 Base64 是因为我们确信这 64 个字符永远不会被破坏/误解。但是通过同样的逻辑,任何不属于 base64 字符的文本字符都可能被破坏/误解。那么为什么 base64 只用于编码 binary 数据呢?扩展同样的思路,当我们使用浏览器时,javascripthtml文件是以base64形式传输的吗?

【问题讨论】:

【参考方案1】:

使用 Base64 有两个原因:

    不是 8 位干净的系统。这源于“以前”,一些系统认真对待 ASCII,只考虑(并传输)任何 8 位字节中的 7 位(因为 ASCII 仅使用 7 位,这将是“好的”,只要所有内容实际上都是ASCII)。 8 位干净的系统,但尝试使用特定编码对数据进行解码(即它们假定它是格式正确的文本)。

在通过它传输二进制(即非文本)数据时,这两者都会产生类似的效果:它们会尝试将二进制数据解释为显然没有意义的字符编码中的文本数据(因为那里 二进制数据中没有字符编码),因此以不可修复的方式修改数据。

Base64 以一种相当简洁的方式解决了这两个问题:它将所有可能的二进制数据流映射为有效的 ASCII 文本:第 8 位永远不会在 Base64 编码的数据上设置,因为只使用常规的旧 ASCII 字符。

这几乎也解决了第二个问题,因为最常用的字符编码(除了 UTF-16 和 UCS-2 之外,还有一些较少使用的字符)是 ASCII 兼容的,这意味着:所有有效ASCII 流恰好也是大多数常见编码中的有效流并表示相同的字符(这些编码的示例是 ISO-8859-* 系列、UTF-8 和大多数 Windows 代码页)。

关于你的第二个问题,答案是双重的:

    文本数据通常带有某种元数据(HTTP 标头或数据内的元标记),用于描述用于解释它的编码。为处理此类数据而构建的系统可以理解、容忍或解释这些标签。 在某些 情况下(尤其是对于邮件传输),我们确实必须使用各种编码技术来确保文本不会被破坏。这可能是使用带引号的可打印编码,有时甚至是在 Base64 中包装文本数据。

最后但同样重要的是:Base64 有一个严重的缺点,那就是它效率低下。对于每 3 个字节的数据进行编码,它会产生 4 个字节的输出,从而将数据的大小增加了约 33%。这就是为什么在不必要的时候应该避免它。

【讨论】:

在典型的客户端服务器模型中,我访问的网站基本上只是我的浏览器向网站服务器请求网页。服务器将发送一个二进制流,该流代表嵌入了图像的网页。为简单起见,我们假设网页只是 HTML。现在,这个二进制流将被切割成网络数据包并通过多个路由器的路由转发到我的浏览器。对于我的第一个问题,8 位干净/不干净的机器在哪里适合这个架构? @driewguy:在示例中,您没有给出任何内容。 HTTP 是 8 位干净的,并且一直如此。受此问题影响的主要是较旧的协议(SMTP 是主要示例)。在当今的网络中仍然使用 Base64 的原因是在 HTML 中嵌入图像(使用base64: URL):HTML 是文本数据,有人决定在其中嵌入图像(二进制数据)。这是案例 #2 的一个示例。 您提到文本数据伴随着元数据,这有助于在中间机器上解码(尽管我不确定为什么中间机器需要解码它接收到的数据,因此是第一个问题)。然后我们可以应用类似的想法,并为非文本数据附带一些元数据,这些元数据基本上是说,不要以任何方式解释它。也许我理解错了。让我们再举一个例子。 'A' 的 ascii 值为 65。那么,如果 HTML 文件从服务器传输到客户端(将以二进制数据包的形式),为什么不会错误地解释 'A'? 我们可以。但我们没有。因为协议是为一种用途而编写的,并以某种方式定义(例如,使用 SMTP 将短文本消息作为邮件发送)。然后有人找到了另一种使用它们的方法(例如发送实际的二进制文件),但不能/不能等待所有标准及其实现的更新。因此,他们开发了一种解决方法(例如 Base64 编码,以通过设计为仅传输 ASCII 文本的系统传输二进制数据)。 所以你的意思是 Base64 只有在嵌入二进制数据(图像)的文本数据通过 HTTP 以外的协议传输时才有用?但就网站而言,HTTP 无处不在。那么为什么我们需要在 HTML 中嵌入 base64 格式的图片呢?【参考方案2】:

BASE64 的一个用途是发送电子邮件。

邮件服务器使用终端来传输数据。翻译也很常见,例如\c\r 变成一个 \n ,反之亦然。注意:也不能保证可以使用 8 位(电子邮件标准是旧的,并且它也允许非“互联网”电子邮件,因此使用 ! 而不是 @)。此外,系统可能不完全是 ASCII。

同样\n\n.被认为是body的结尾,mboxes也使用\n>From来标记新邮件的开始,所以同样当8位标志在邮件服务器中很常见时,问题并没有完全解决。

BASE64 是解决所有问题的好方法:内容只是作为所有服务器都必须知道的字符发送,而编码/解码问题只需要发送方和接收方协议(以及正确的程序),而无需担心许多中间的中继服务器。注意:所有\c\r\n 等都会被忽略。

注意:您也可以使用 BASE64 对 URL 中的字符串进行编码,而不必担心网络浏览器的解释。您可能还会在配置文件中看到 BASE64(例如,包含图标):特殊制作的图像可能不会被解释为配置。只需 BASE64 就可以方便地将二进制数据编码为不是为二进制数据设计的协议。

【讨论】:

以上是关于为啥“仅”使用 Base64 来编码二进制数据?的主要内容,如果未能解决你的问题,请参考以下文章

如果输入长度不能被 3 整除,为啥 base64 编码需要填充?

Base64编码及iOS中的Base64

Base64编码

密码学Base64 编码 ( Base64 简介 | Base64 编码原理 | 最后编码组字节不足时补位 ‘=‘ 符号 | Base64 编码实现参考 )

为啥要用base64编码来保存图片?

base64模块的使用