mobile wallpaper 1
mobile wallpaper 2
mobile wallpaper 3
mobile wallpaper 4
932 字
3 分钟
Base64详解与JavaScript中的使用
2024-03-25
2025-12-10

简介#

Base64 是一种将任意二进制数据转换为可打印 ASCII 字符的编码方式。它本质上是 二进制 → 文本 的编码方案,常用于网络传输或文本协议中嵌入二进制数据。

一个常见的误区是将 Base64 看作为加密算法,实际上 Base64 只是一种编码方式,不具备加密功能。

Base64 使用 6 bit 表示一个字符,因此有 2^6 = 64 个不同字符,编码表包含:

  • 26 个大写字母
  • 26 个小写字母
  • 10 个数字
  • 2 个符号:+/
  • = 用于填充

下面是标准 Base64 编码表:

ValueEncodingValueEncodingValueEncodingValueEncoding
0A16Q32g48w
1B17R33h49x
2C18S34i50y
3D19T35j51z
4E20U36k520
5F21V37l531
6G22W38m542
7H23X39n553
8I24Y40o564
9J25Z41p575
10K26a42q586
11L27b43r597
12M28c44s608
13N29d45t619
14O30e46u62+
15P31f47v63/

编码步骤#

当对字符串进行 Base64 时,必须先根据某种字符集(通常是 UTF-8)将字符串编码为字节数据,然后再进行 Base64 转换。 如果字符串仅包含 ASCII 字符,此时所有字符编码均为单字节,计算过程简单。

下面以字符串 Mari 为例,演示 ASCII 情况的 Base64 编码步骤。

Array.from( "Mari" )
.map( item => item.charCodeAt(0) ) // [77, 97, 114, 105]
.map( item => item.toString(2).padStart(8, "0") ) // ["01001101", "01100001", "01110010", "01101001"]
.join( "" ) // "01001101011000010111001001101001"

在得到二进制数据后,Base64 将其按照 6 位一组进行分割,分割后不足 6 位在后面补零。

根据上面得到的结果,分割后得到:

010011 010110 000101 110010 011010 010000
19 22 5 50 26 16

然后将每一位根据 Base64 编码表进行转换,得到:

TWFyaQ

Base64 编码后的字符串长度需要为 4 的倍数,如果不足则需要使用 = 补充,因此对上方的结果作最后补充处理,得到:

TWFyaQ==

这就是 Base64 的编码步骤,依次方式反向操作也可以将 Base64 编码的字符串解码为原始数据。

JavaScript 中的操作方法#

JavaScript 提供了 btoaatob 用于 Base64 编解码:

btoa( "Mari" ) // "TWFyaQ=="
atob( "TWFyaQ==" ) // "Mari"

需要注意:btoa 只能处理 Latin1(ISO-8859-1)字符,即 单字节范围 0–255。 对于 UTF-8 字符(如中文、emoji),由于实际编码需要多字节,直接调用 btoa 会抛出异常。

"M".codePointAt( 0 ).toString( 2 ) // "1001101" 单字节字符
btoa( "M" ); // "TQ=="
"茉".codePointAt( 0 ).toString( 2 ) // "10011100100010101" 双字节字符
btoa( "茉" ); // Uncaught DOMException: Failed to execute 'btoa' on 'Window': The string to be encoded contains characters outside of the Latin1 range.

因此在现代 JavaScript 中,处理非 ASCII 字符(UTF-8)时,需要先将字符串转换为 UTF-8 字节,此时存在两种常见方式:

使用 TextEncoder / TextDecoder(推荐)#

这种方式最规范,可以配合文件、网络流等使用。生成的 Base64 与其他语言完全兼容,即接收到后直接解码即可,无须额外处理。

function base64Encode( str ) {
const bytes = new TextEncoder().encode( str );
let binary = "";
for ( const b of bytes ) binary += String.fromCharCode( b );
return btoa( binary );
}
function base64Decode( str ) {
const binary = atob( str );
const bytes = Uint8Array.from( binary, c => c.charCodeAt( 0 ) );
return new TextDecoder().decode( bytes );
}
base64Encode( "茉莉" ); // "6IyJ6I6J"
base64Decode( "6IyJ6I6J" ); // "茉莉"

encodeURIComponent 方案#

这个方案有几个缺陷:

  • 无法处理二进制数据,只适用于文本字符串
  • 其他语言/环境接收到 Base64 编码后无法直接解码为原始字符串,需要多进行一步 URL decode
  • 性能较差

其本质是分几个步骤:

  1. 先将字符串用 encodeURIComponent 转为百分号编码字符串
  2. 再将百分号编码字符串传入 btoa 进行 Base64 编码
  3. 解码时反向操作,即先用 atob 解码 Base64,再用 decodeURIComponent 转回原始字符串

此时他是对“百分号文本”编码,而不是对“原始字符串”编码,这是非常不标准也不方便使用的

function base64Encode( str ) {
return btoa( encodeURIComponent( str ) );
}
function base64Decode( str ) {
return decodeURIComponent( atob( str ) );
}
base64Encode( "茉莉" ); // "JUU4JThDJTg5JUU4JThFJTg5"
base64Decode( "JUU4JThDJTg5JUU4JThFJTg5" ); // "茉莉"
分享

如果这篇文章对你有帮助,欢迎分享给更多人!

Base64详解与JavaScript中的使用
https://marrydream.top/posts/web前端/base64详解与javascript中的使用/
作者
茉铃
发布于
2024-03-25
许可协议
CC BY-NC-SA 4.0

部分信息可能已经过时

目录