普通视图

发现新文章,点击刷新页面。
昨天 — 2025年1月17日首页

在 JavaScript 中处理中文字符串的 Base64 编码与解码

作者 red润
2025年1月17日 09:43

在 JavaScript 中处理中文字符串的 Base64 编码与解码

在 Web 开发中,Base64 编码是一种常见的数据转换方式。它通过将二进制数据转换为文本数据,便于在 HTTP 请求、URL 中传输或存储。然而,处理中文字符时,Base64 编码会面临一些特殊的挑战,因为中文字符通常占用多个字节,而 Base64 编码是基于字节的。在本文中,我们将介绍两种方法来处理中文字符串的 Base64 编码与解码。


为什么 Base64 编码会与中文字符发生冲突?

Base64 编码是一种将二进制数据转换为 ASCII 字符串格式的方式。每个字符占用 6 位,而 Base64 编码本身的原理是将输入数据按照每 6 位拆分,并映射到对应的 Base64 字符上。

然而,中文字符在 UTF-8 编码下通常需要多个字节(通常是 3 个字节)。因此,如果我们直接对中文字符进行 Base64 编码而没有正确处理字符编码,可能会导致编码错误或者解码时出现乱码。为了避免这个问题,我们需要先将中文字符转换为 UTF-8 字节,然后再进行 Base64 编码。

在本文中,我们将介绍两种不同的方式来解决这个问题,分别是手动实现 Base64 编码和解码的方式,以及使用 TextEncoderTextDecoder API 来处理编码和解码。


方法一:手动实现 Base64 编码与解码

在这个方法中,我们手动处理每个字节,并将字节转化为二进制字符串。然后,我们将二进制字符串按每 6 位进行拆分,映射为 Base64 字符。解码时,我们通过反向操作将 Base64 字符还原为二进制数据,然后恢复为原始的 UTF-8 字符串。

(1) 中文字符串的 Base64 编码
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
解释:
  • UTF-8 编码:通过 TextEncoder().encode(input) 方法,我们将输入的中文字符串转换为 UTF-8 字节。每个字节在 UTF-8 编码中通常会占用多个字节(例如中文字符通常占用 3 个字节)。
  • 二进制转换:我们将每个字节转为二进制字符串,并将它们合并成一个长的二进制串。
  • Base64 编码:通过按每 6 位将二进制字符串拆分,我们将每一组 6 位的二进制数转换为对应的 Base64 字符。
  • 填充字符:Base64 编码要求输出的字符数必须是 4 的倍数,因此我们在末尾添加 = 字符进行填充。
(2) 中文字符串的 Base64 解码
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!
解释:
  • Base64 解码:首先将 Base64 字符串转换为 6 位二进制字符串。然后每 8 位恢复为一个字节。
  • 还原字符:通过 TextDecoder 将解码后的字节数组还原为 UTF-8 字符串。

3. 方法二:使用 TextEncoderTextDecoder API

如果不想手动实现 Base64 编码和解码的过程,现代浏览器提供了 TextEncoderTextDecoder API,可以帮助我们简化编码和解码过程。我们可以直接使用这些 API 来将中文字符串转换为字节数组,再进行 Base64 编码。

(1) 中文字符串的 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:通过 TextEncoder 将字符串转换为 UTF-8 字节数组。
  • btoabtoa 是一个内建的 JavaScript 函数,用于将二进制数据转换为 Base64 编码的字符串。需要注意的是,btoa 只能处理 8 位字符,因此我们通过 String.fromCharCode.apply 方法将字节数组转换为字符串,然后进行编码。
(2) 中文字符串的 Base64 解码
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!
解释:
  • atobatob 函数用于解码 Base64 字符串。解码后的数据是一个原始的二进制字符串。
  • TextDecoder:通过 TextDecoder 将字节数组还原为 UTF-8 字符串。

4. 总结

在处理中文字符串的 Base64 编码与解码时,关键在于如何正确地将字符转换为字节数据。通过手动处理每个字节或使用现代的 TextEncoderTextDecoder API,我们可以确保中文字符能够正确地进行 Base64 编码与解码。

  • 手动实现:适用于那些需要详细控制编码过程的场景。你可以深入理解 Base64 编码的每个细节,并根据需要进行优化。
  • 使用 API:对于大多数情况,TextEncoderTextDecoder API 提供了一种更简洁、直接的方式来处理编码和解码,减少了手动操作的复杂性。

理解 Base64 编码原理及其 JavaScript 实现

作者 red润
2025年1月17日 09:30

理解 Base64 编码原理及其 JavaScript 实现

image.png

注意:这里没有处理中文base64编码情况

什么是 Base64 编码?

Base64 编码是一种将二进制数据转换为可打印字符的编码方式。它将每三个字节(24 位)的二进制数据转换为四个字符,每个字符由64个字符集合中的一个表示。这使得数据可以通过文本协议传输(如电子邮件、HTTP 请求等),而不会出现二进制数据引起的字符编码问题。

Base64 编码的基本原理

Base64 的基本思想是将输入数据(通常是二进制数据)以特定的方式转换成字符。具体地,它将输入数据分为每三字节(24 位),然后将每个三字节块拆分成四个 6 位的块(因为每个 Base64 编码字符对应 6 位二进制数据)。这些 6 位的块通过查表得到对应的 Base64 字符。

Base64 字符集

Base64 的字符集包含 64 个字符,包括:

  • 大写字母:A-Z(26 个字符)
  • 小写字母:a-z(26 个字符)
  • 数字:0-9(10 个字符)
  • 特殊字符:+/(2 个字符)

这个字符集是标准的 Base64 编码字符集。

编码过程

  1. 将输入数据按 3 字节分组:每三个字节组成一个 24 位的二进制数据块。
  2. 将 24 位数据分成四个 6 位的数据块
  3. 查找字符集中的对应字符:每 6 位对应字符集中的一个字符。
  4. 处理剩余的字节:如果输入数据的字节数不是 3 的倍数,那么需要在末尾添加 = 作为填充。

示例:

假设我们要对字符串 "Man" 进行 Base64 编码:

  1. 将 "Man" 转换为二进制数据:

    M -> 01001101
    a -> 01100001
    n -> 01101110
    
  2. 将这三个字符的二进制数据拼接起来,得到 24 位:

    010011010110000101101110
    
  3. 将这 24 位数据分成四个 6 位的数据块:

    010011 010110 000101 101110
    
  4. 查找字符集中的对应字符:

    010011 -> 19 -> T
    010110 -> 22 -> W
    000101 -> 5 -> F
    101110 -> 46 -> u
    
  5. 最终结果就是 TWFu

使用 JavaScript 实现 Base64 编码

现在,让我们用 JavaScript 来实现 Base64 编码的过程。JavaScript 提供了内置的 btoa()atob() 函数,但这里我们将手动实现 Base64 编码和解码过程,以便更深入地理解其背后的原理。

Base64 编码实现

function base64Encode(input) {
    const base64Chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
    
    // 将输入字符串转换为二进制字符串
    let binaryString = '';
    for (let i = 0; i < input.length; i++) {
        binaryString += input.charCodeAt(i).toString(2).padStart(8, '0'); // 每个字符转为8位二进制
    }

    // 按 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 = 'redrun base64';
const encoded = base64Encode(input);
console.log('Encoded:', encoded);// Encoded: cmVkcnVuIGJhc2U2NA==

Base64 解码实现

Base64 解码的过程与编码类似,只不过是将 Base64 字符转换回二进制数据,然后再转换为原始字符串。

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 decodedString = '';
    for (let i = 0; i < binaryString.length; i += 8) {
        const byte = binaryString.slice(i, i + 8);
        decodedString += String.fromCharCode(parseInt(byte, 2)); // 将二进制转为字符
    }

    return decodedString;
}

// 示例
const decoded = base64Decode(encoded);
console.log('Decoded:', decoded);// Decoded: redrun base64

完整的 Base64 编码解码演示

// 示例
const input = 'redrun base64';
const encoded = base64Encode(input);
console.log('Encoded:', encoded);// Encoded: cmVkcnVuIGJhc2U2NA==

// 示例
const decoded = base64Decode(encoded);
console.log('Decoded:', decoded);// Decoded: redrun base64

总结

  • Base64 编码 是一种常见的数据编码方式,广泛用于数据传输,尤其是在 HTTP 请求、电子邮件等场景中。
  • Base64 将每 3 个字节的二进制数据编码为 4 个字符,编码后的数据仅包含可打印字符,便于传输。
  • 在 JavaScript 中,可以通过自定义函数实现 Base64 编码和解码,了解其中的原理有助于更深入地掌握数据处理和编码技术。
❌
❌