在 Web 开发中,Base64 编码是一种常见的数据转换方式。它通过将二进制数据转换为文本数据,便于在 HTTP 请求、URL 中传输或存储。然而,处理中文字符时,Base64 编码会面临一些特殊的挑战,因为中文字符通常占用多个字节,而 Base64 编码是基于字节的。在本文中,我们将介绍两种方法来处理中文字符串的 Base64 编码与解码。
Base64 编码是一种将二进制数据转换为 ASCII 字符串格式的方式。每个字符占用 6 位,而 Base64 编码本身的原理是将输入数据按照每 6 位拆分,并映射到对应的 Base64 字符上。
然而,中文字符在 UTF-8 编码下通常需要多个字节(通常是 3 个字节)。因此,如果我们直接对中文字符进行 Base64 编码而没有正确处理字符编码,可能会导致编码错误或者解码时出现乱码。为了避免这个问题,我们需要先将中文字符转换为 UTF-8 字节,然后再进行 Base64 编码。
在本文中,我们将介绍两种不同的方式来解决这个问题,分别是手动实现 Base64 编码和解码的方式,以及使用 TextEncoder
和 TextDecoder
API 来处理编码和解码。
在这个方法中,我们手动处理每个字节,并将字节转化为二进制字符串。然后,我们将二进制字符串按每 6 位进行拆分,映射为 Base64 字符。解码时,我们通过反向操作将 Base64 字符还原为二进制数据,然后恢复为原始的 UTF-8 字符串。
function base64Encode(input) {
const base64Chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
// 将字符串转换为 UTF-8 字节
let utf8Bytes = new TextEncoder().encode(input);
// 将每个字节转换为二进制字符串
let binaryString = '';
for (let i = 0; i < utf8Bytes.length; i++) {
binaryString += utf8Bytes[i].toString(2).padStart(8, '0');
}
// 按 6 位拆分
const chunks = [];
for (let i = 0; i < binaryString.length; i += 6) {
chunks.push(binaryString.slice(i, i + 6));
}
// 如果最后一组少于 6 位,进行填充
if (chunks[chunks.length - 1].length < 6) {
chunks[chunks.length - 1] = chunks[chunks.length - 1].padEnd(6, '0');
}
// 查找对应的 Base64 字符
let base64Encoded = chunks.map(chunk => {
const index = parseInt(chunk, 2); // 将二进制转换为数字
return base64Chars.charAt(index);
}).join('');
// 添加填充字符
while (base64Encoded.length % 4 !== 0) {
base64Encoded += '=';
}
return base64Encoded;
}
// 示例
const input = '你好润,Base64!';
const encoded = base64Encode(input);
console.log('Encoded:', encoded);// Encoded: 5L2g5aW95ram77yMQmFzZTY077yB
TextEncoder().encode(input)
方法,我们将输入的中文字符串转换为 UTF-8 字节。每个字节在 UTF-8 编码中通常会占用多个字节(例如中文字符通常占用 3 个字节)。=
字符进行填充。function base64Decode(input) {
const base64Chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
// 去除填充字符 '='
input = input.replace(/=/g, '');
// 将每个 Base64 字符转换为 6 位二进制
let binaryString = '';
for (let i = 0; i < input.length; i++) {
const index = base64Chars.indexOf(input.charAt(i)); // 查找字符的位置
binaryString += index.toString(2).padStart(6, '0'); // 将位置转换为 6 位二进制
}
// 每 8 位一个字节,转换为字节
let decodedBytes = [];
for (let i = 0; i < binaryString.length; i += 8) {
const byte = binaryString.slice(i, i + 8);
decodedBytes.push(parseInt(byte, 2)); // 将二进制转为字节
}
// 将字节数组转换为 UTF-8 字符串
let decodedString = new TextDecoder().decode(new Uint8Array(decodedBytes));
return decodedString;
}
// 示例
const decoded = base64Decode(encoded);
console.log('Decoded:', decoded);//Decoded: 你好润,Base64!
TextDecoder
将解码后的字节数组还原为 UTF-8 字符串。TextEncoder
和 TextDecoder
API如果不想手动实现 Base64 编码和解码的过程,现代浏览器提供了 TextEncoder
和 TextDecoder
API,可以帮助我们简化编码和解码过程。我们可以直接使用这些 API 来将中文字符串转换为字节数组,再进行 Base64 编码。
function base64EncodeUsingAPI(input) {
// 使用 TextEncoder 将字符串转换为 UTF-8 字节
const utf8Bytes = new TextEncoder().encode(input);
// 将字节数组转换为 Base64 字符串
return btoa(String.fromCharCode.apply(null, utf8Bytes));
}
// 示例
const input = '你好red润,Base64!';
const encoded = base64EncodeUsingAPI(input);
console.log('Encoded:', encoded);//Encoded: 5L2g5aW9cmVk5ram77yMQmFzZTY077yB
TextEncoder
将字符串转换为 UTF-8 字节数组。btoa
:btoa
是一个内建的 JavaScript 函数,用于将二进制数据转换为 Base64 编码的字符串。需要注意的是,btoa
只能处理 8 位字符,因此我们通过 String.fromCharCode.apply
方法将字节数组转换为字符串,然后进行编码。function base64DecodeUsingAPI(input) {
// 使用 atob 解码 Base64 字符串
const decodedData = atob(input);
// 将解码后的字符串转换为字节数组
const byteArray = new Uint8Array(decodedData.length);
for (let i = 0; i < decodedData.length; i++) {
byteArray[i] = decodedData.charCodeAt(i);
}
// 使用 TextDecoder 将字节数组转换为原始字符串
return new TextDecoder().decode(byteArray);
}
// 示例
const decoded = base64DecodeUsingAPI(encoded);
console.log('Decoded:', decoded);// Decoded: 你好red润,Base64!
atob
:atob
函数用于解码 Base64 字符串。解码后的数据是一个原始的二进制字符串。TextDecoder
将字节数组还原为 UTF-8 字符串。在处理中文字符串的 Base64 编码与解码时,关键在于如何正确地将字符转换为字节数据。通过手动处理每个字节或使用现代的 TextEncoder
和 TextDecoder
API,我们可以确保中文字符能够正确地进行 Base64 编码与解码。
TextEncoder
和 TextDecoder
API 提供了一种更简洁、直接的方式来处理编码和解码,减少了手动操作的复杂性。