为什么我们使用Base64?


275

维基百科

当需要对二进制数据进行编码时,通常需要使用Base64编码方案,该二进制数据需要在旨在处理文本数据的媒体上存储和传输。这是为了确保数据在传输过程中保持不变。

但是,不是因为我们的计算机存储的二进制数据就一直以二进制形式存储/传输数据,而这仅取决于您如何解释它?因此,无论您编码位模式010011010110000101101110ManASCII或如TWFu为Base64,你最终将存储相同的位模式。

如果最终编码是用零和一表示的,并且每台机器和媒体都可以处理它们,那么将数据表示为ASCII还是Base64有什么关系呢?

“旨在处理文本数据的媒体”是什么意思?他们可以处理二进制=>他们可以处理任何东西。


谢谢大家,我想我现在明白了。

当我们发送数据时,我们不能确定数据将以我们期望的格式解释。因此,我们发送双方都可以理解的以某种格式(如Base64)编码的数据。这样,即使发送方和接收方对相同内容的解释不同,但由于它们在编码格式上达成共识,因此不会错误地解释数据。

Mark Byers为例

如果我要发送

Hello
world!

一种方法是像ASCII一样发送

72 101 108 108 111 10 119 111 114 108 100 33

但是字节10在另一端可能无法正确解释为换行符。因此,我们使用ASCII的子集对其进行编码,如下所示

83 71 86 115 98 71 56 115 67 110 100 118 99 109 120 107 73 61 61

即使在接收器碰巧对其余字符集有不同的解释的情况下,以相同信息量传输更多数据为代价,这也确保了接收器可以按预期方式解码数据。


6
历史背景:电子邮件服务器以前是7位ASCII。他们中的许多人会将高位设置为0,因此您只需要发送7位值。参见en.wikipedia.org/wiki/Email#Content_encoding
Harold L'2010年

53
我们使用的base64,因为它更具可读性比Perl
马丁

2
@马丁,你在开玩笑。Perl很难阅读,但是base64根本不可读。
彼得·朗

1
@Lazer您的图片丢失了
Mick

2
@Lazer,“但是字节10可能无法在另一端正确解释为换行符。” 为什么?双方已经就ASCII达成了一致,他们必须正确解释它!
ProgramCpp

Answers:


298

您的第一个错误是认为ASCII编码和Base64编码可以互换。他们不是。它们用于不同的目的。

  • 当您以ASCII编码文本时,您将从文本字符串开始并将其转换为字节序列。
  • 在Base64中对数据进行编码时,您将从字节序列开始并将其转换为文本字符串。

要了解为什么首先需要Base64,我们需要一些计算历史。


计算机以二进制形式(0和1)进行通信,但是人们通常希望与更丰富的表单数据(例如文本或图像)进行通信。为了在计算机之间传输此数据,首先必须将其编码为0和1,然后发送,然后再次解码。以文本为例-有许多不同的方法可以执行此编码。如果我们都可以同意一个编码,这会简单得多,但不幸的是事实并非如此。

最初创建了许多不同的编码(例如Baudot码),每个字符使用不同数量的位,直到最终ASCII成为每个字符7位的标准。但是,大多数计算机将二进制数据存储在每个字节由8位组成的字节中,因此ASCII不适合传输此类数据。有些系统甚至会擦除最高位。此外,跨系统的行尾编码的差异意味着有时还会修改ASCII字符10和13。

为了解决这些问题,引入了Base64编码。这样,您就可以将ribribry字节编码为已知可以安全发送而不损坏的字节(ASCII字母数字字符和几个符号)。缺点是使用Base64编码消息会增加其长度-每3个字节的数据会编码为4个ASCII字符。

发送文本可靠,你可以编码,使用您的选择(例如UTF-8),然后的文本编码字节的Base64编码生成的二进制数据转换为文本字符串,它是安全发送编码为ASCII。接收者将不得不逆转此过程以恢复原始消息。当然,这要求接收者知道使用了哪种编码,并且该信息通常需要单独发送。

从历史上看,它已用于对电子邮件中的二进制数据进行编码,其中电子邮件服务器可能会修改行尾。一个更现代的示例是使用Base64编码将图像数据直接嵌入HTML源代码中。在这里,有必要对数据进行编码,以避免像“ <”和“>”这样的字符被解释为标签。


这是一个工作示例:

我希望发送一条两行的短信:

你好
世界!

如果以ASCII(或UTF-8)格式发送,则如下所示:

72 101 108 108 111 10 119 111 114 108 100 33

字节10在某些系统中已损坏,因此我们可以将这些字节以64为基数编码为Base64字符串:

SGVsbG8sCndvcmxkIQ ==

使用ASCII编码时,如下所示:

83 71 86 115 98 71 56 115 67 110 100 118 99 109 120 107 73 61 61

这里的所有字节都是已知的安全字节,因此几乎没有任何系统会破坏此消息的机会。我可以发送此消息而不是原始消息,然后让接收者撤消该过程以恢复原始消息。


4
“大多数现代通信协议都不会破坏数据”-尽管例如,电子邮件可能会损坏,但在将邮件保存到邮箱时,使用传递代理将字符串“ \ nFrom”替换为“ \ n> From”。或HTTP标头以换行符结尾,并且没有可逆的方式来转义数据中的换行符(行连续性使空格占空),因此您也不能将任意ASCII转储到它们中。base64 不仅比7位安全性好,而且还是字母数字和-= + /安全的。
史蒂夫·杰索普

1
“缺点是使用Base64编码消息会增加其长度-每3个字节的数据就会编码为4个字节。” 如何增加到4个字节?会不会仍然只有3 * 8 = 24位?
Lazer

4
@Lazer:不。看您自己的示例-“ Man”是base-64编码的“ TWFu”。3个字节-> 4个字节。这是因为允许输入为2 ^ 8 = 256个可能的字节中的任何一个,而输出仅使用2 ^ 6 = 64个字节(和=,以帮助指示数据的长度)。为了避免输出即使包含输入也包含任何“令人兴奋”的字符,“浪费”了每个四方输出的8位。
史蒂夫·杰索普

2
将“在Base64中对数据进行编码时,从一个字节序列开始并将其转换为文本字符串”可能会重新声明为“在Base64中对数据进行编码时,从一个字节序列开始并将其转换为一个字节序列”可能会有所帮助。仅由ASCII值组成的字节序列”。SMTP要求仅由ASCII字符组成的字节序列,这就是为什么将Base64(和带引号的可打印内容)用作内容传输编码的原因。优秀的概述!
ALEXintlsos

1
我会投票,但有64票。对不起,这很完美。
杰西Catrinck

61

用XML编码二进制数据

假设您要在XML文档中嵌入几个图像。图像是二进制数据,而XML文档是文本。但是XML无法处理嵌入式二进制数据。你是怎么做到的?

一种选择是将图像编码为base64,将二进制数据转换为XML可以处理的文本。

代替:

<images>
  <image name="Sally">{binary gibberish that breaks XML parsers}</image>
  <image name="Bobby">{binary gibberish that breaks XML parsers}</image>
</images>

你做:

<images>
  <image name="Sally" encoding="base64">j23894uaiAJSD3234kljasjkSD...</image>
  <image name="Bobby" encoding="base64">Ja3k23JKasil3452AsdfjlksKsasKD...</image>
</images>

XML解析器将能够正确解析XML文档并提取图像数据。


这可能是Microsoft旧.mht格式的工作方式(HTML文件+图像在一个文件中)。
Sridhar Sarnobat,

38

为什么不查看当前定义Base64的RFC

数据的基本编码在许多情况下用于存储或传输
数据,这些环境可能出于遗留原因而仅限于US-ASCII [1]数据。基本编码也可以用于没有遗留限制的新应用程序中,仅仅因为它使得使用文本编辑器来操作对象成为可能。

过去,不同的应用程序有不同的要求,因此有时以略有不同的方式实现基本编码。如今,协议规范有时通常会使用基本编码,特别是使用“ base64”,而没有精确的描述或参考。多用途Internet邮件扩展(MIME)[4]通常用作base64的参考,而没有考虑换行或非字母字符的后果。本规范的目的是建立常见的字母和编码注意事项。这有望减少其他文档中的歧义,从而提高互操作性。

Base64最初被设计为允许将二进制数据作为多用途Internet邮件扩展的一部分附加到电子邮件的方法。


26

当然,用于文本数据的媒体最终也将是二进制的,但是文本媒体通常使用某些二进制值作为控制字符。同样,文本媒体可能会拒绝某些二进制值作为非文本。

Base64编码将二进制数据编码为只能在文本媒体中解释为文本的值,并且不含任何特殊字符和/或控制字符,因此数据也将在文本媒体中保留。


因此,与Base64一样,大多数源和目标都将以相同的方式解释数据,因为即使它们以不同的方式解释控制字符,它们也很有可能以相同的方式解释这64个字符。那正确吗?
Lazer

6
他们的数据甚至可能在运输过程中被破坏。例如,如果服务器和客户端的操作系统不匹配,并且传输被标记为文本模式,则许多FTP程序会将行尾从13,10重写为10,反之亦然。FTP只是我想到的第一个示例,它不是一个好例子,因为FTP确实支持二进制模式。
亨德里克·布鲁默曼

@nhnb:我认为FTP是一个很好的例子,因为它表明文本模式不适用于需要二进制数据的事物。
jamesdlin

什么是文字媒体?
Koray Tugay

18

媒体验证的更多字符串编码的更多,因此我们要确保处理应用程序可以接受该数据(例如,不包含表示EOL的二进制序列)

假设您要在电子邮件中以UTF-8编码发送二进制数据-如果一比特和零比特流创建了一个序列,则电子邮件可能无法正确显示不是UTF-8编码的有效Unicode,则。

当我们要在URL本身中编码对URL无效的字符时,URL中会发生相同类型的事情:

http://www.foo.com/hello我的朋友-> http://www.foo.com/hello%20my%20friend

这是因为我们要在一个认为该空间有臭味的系统上发送空间。

我们正在做的是确保在已知的良好,可接受且无害的位序列与另一个字面量的位序列之间存在一对一的映射,并且处理应用程序不区分编码。

在您的示例中,man可能是第一种形式的有效ASCII;但通常您可能希望传输随机二进制值(即,通过电子邮件发送图像):

MIME版本:1.0
内容描述:“ a.gif的Base64编码”
内容类型:image / gif;name =“ a.gif”
Content-Transfer-Encoding:Base64
Content-Disposition:附件;filename =“ a.gif”

在这里,我们看到GIF图像在base64中编码为电子邮件的一部分。电子邮件客户端读取标头并对其进行解码。由于编码的原因,我们可以确保GIF不包含任何可能被解释为协议的内容,并且避免插入SMTP或POP可能认为重要的数据。


1
太棒了-这个解释使它点击了。这并不是要混淆或压缩数据,而只是避免使用可以解释为协议的特殊序列。
帕特里克·迈克尔森

13

Base64而不是转义特殊字符

我将给您一个非常不同但真实的示例:我编写要在浏览器中运行的javascript代码。HTML标记具有ID值,但是对ID中有效的字符有限制。

但是我希望我的ID无损地引用文件系统中的文件。现实中的文件中可能有各种奇怪和奇妙的字符,包括感叹号,重音字符,波浪号甚至表情符号!我不能做到这一点:

<div id="/path/to/my_strangely_named_file!@().jpg">
    <img src="http://myserver.com/path/to/my_strangely_named_file!@().jpg">
    Here's a pic I took in Moscow.
</div>

假设我想运行一些这样的代码:

# ERROR
document.getElementById("/path/to/my_strangely_named_file!@().jpg");

我认为这段代码在执行时会失败。

使用Base64,我可以引用复杂的内容,而不必担心哪种语言允许哪些特殊字符以及哪些需要转义:

document.getElementById("18GerPD8fY4iTbNpC9hHNXNHyrDMampPLA");

与使用MD5或其他某种哈希函数不同,您可以反转编码以找出真正有用的数据。

我希望我在几年前了解Base64。我本来可以避免用'encodeURIComponent '和str.replace(‘\n’,’\\n’)

SSH传输文本:

如果您尝试通过ssh传递复杂的数据(例如,一个点文件,以便可以对自己的shell进行个性化设置),那么在没有Base 64的情况下就可以这样做。这就是使用base 64的方式(我知道您可以使用SCP,但这将需要多个命令-将键绑定到服务器时会使键绑定变得复杂):


12

我发现方便的一个例子是尝试将二进制数据嵌入XML中。SAX解析器误解了一些二进制数据,因为这些数据实际上可以是任何东西,包括XML特殊字符。Base64在发送端对数据进行编码并在接收端对其进行解码解决了该问题。


1
+1-但这绝不是SAX特有的。任何XML解析器(即DOM或XLINQ)都会发生这种情况。
Billy ONeal,2010年

1
@比利:是的,绝对。我只是碰巧对该应用程序使用了SAX解析器。
比尔蜥蜴

不同的引擎,例如SAX解析器,可能以不同的方式(不同的控制字符)解释某些ASCII值。因此,这里的想法是使用普遍具有通用含义的ASCII子集。对?
Lazer

1
@Lazer:对。当您尝试将未解释的二进制数据解释为ASCII时,偶然会在其中包含控制字符(在这种情况下不是)。
比尔蜥蜴

10

大多数计算机以8位二进制格式存储数据,但这不是必需的。某些机器和传输媒体一次只能处理7位(甚至更少)。这样的媒体将以7位的倍数解释流,因此,如果要发送8位数据,则​​不会收到另一端的期望。Base-64只是解决此问题的一种方法:将输入编码为6位格式,通过介质发送,然后在接收端将其解码回8位格式。


3
如果流在7位之后中断,为什么会出现问题。最后,另一台机器将通过流接收所有数据,然后可以选择8位格式进行显示?我心里怎么了!
mallaudin

6

除了其他(有点冗长)的答案:即使忽略仅支持7位ASCII的旧系统,以文本模式提供二进制数据的基本问题还包括:

  • 换行符通常以文本模式转换。
  • 必须注意不要将NUL字节视为文本字符串的末尾,这在任何使用C谱系的程序中都非常容易做到。

还有一些控制字符,例如^ C,^ D和^ Z在某些平台上被解释为文件结尾。
2010年

5

“旨在处理文本数据的媒体”是什么意思?

这些协议旨在处理文本(通常只有英文文本)而不是二进制数据(如.png和.jpg图像)。

他们可以处理二进制=>他们可以处理任何东西。

但是反过来是不正确的。旨在表示文本的协议可能会不适当地处理恰好包含以下内容的二进制数据:

  • 用于行尾的字节0x0A和0x0D,因平台而异。
  • 其他控制字符,例如0x00(NULL = C字符串终止符),0x03(文本结束),0x04(传输结束)或0x1A(DOS文件结束),可能会过早地发出数据结束信号。
  • 0x7F以上的字节(如果协议是为ASCII设计的)。
  • 无效的UTF-8字节序列。

因此,您不能仅通过基于文本的协议发送二进制数据。限于表示非空格非控制ASCII字符的字节,其中有94个。选择Base 64的原因是使用2的幂进行运算速度更快,而64是最大的有效字节。

不过有一个问题。系统仍如何在通用编码技术(如通用UTF-8)上达成共识?

至少在网络上,它们大多数都具有。 大多数网站都使用UTF-8

西方的问题是,有很多旧软件的ass-u-me-s都是1个字节= 1个字符,并且不能与UTF-8一起使用。

东方的问题是它们对GB2312和Shift_JIS之类的编码的附件。

而且微软似乎还没有选择错误的UTF编码。如果要使用Windows API或Microsoft C运行时库,则限于UTF-16或区域设置的“ ANSI”编码。这使使用UTF-8变得很痛苦,因为您必须一直进行转换。


5

为什么/我们如何使用Base64编码?

Base64是效率为75%的二进制到文本编码方案之一。它用于使典型的二进制数据(例如图像)可以通过传统的“非8位干净”通道安全地发送。在早期的电子邮件网络中(直到1990年代初),大多数电子邮件都是7位US-ASCII字符集中的纯文本。因此,许多早期的通信协议标准被设计为在“不是8位干净”的“ 7位”通信链接上工作。方案效率是输入中的位数与编码的输出中的位数之间的比率。十六进制(Base16)也是效率为50%的二进制到文本编码方案之一。

Base64编码步骤(简化):

  1. 二进制数据按每个24位(3个字节)的连续块排列。
  2. 每个24位块被分为四个部分,每个部分6位。
  3. 每个6位组被转换为它们相应的Base64字符值,即Base64编码将三个八位位组转换为四个编码字符。输出字节与输入字节的比率为4:3(33%的开销)。
  4. 有趣的是,相同的字符将根据它们在三字节组中的位置而不同地编码,该三字节组被编码以产生四个字符。
  5. 接收者将不得不逆转此过程以恢复原始消息。

3

“旨在处理文本数据的媒体”是什么意思?

早在ASCII统治时代,处理非ASCII值的世界令人头疼。人们跳过了各种各样的箍,使它们通过导线传输而不会丢失信息。


3
实际上,在过去,甚至没有到处都使用ASCII。许多协议具有用于传输数据的单独的文本模式和二进制模式,不幸的是,电子邮件那时还没有。文本模式之所以必要,正是因为没有单一的文本编码统治世界,而不是ASCII。每个计算机网络都有自己喜欢的编码,因此有些网关的工作是将交换的文本转换为本地编码,以便日本公司无需mojibake即可将电子邮件发送给美国业务顾问。在发送二进制数据时,这种转换显然是不可取的。
Lie Ryan 2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.