我的博客

JavaScript Base64编码

目录

浏览器内置了 btoa 和 atob 用于编码和解码 Base64。使用上主要有两个问题。

  1. 对于IE 浏览器,仅 IE 10 或以上的版本可以支持

  2. 对于非 ASCII 字符报错(参考MDN

    因为 JavaScript 的字符串占两个 byte。但是 Base64 的输入应该是 bytes,所以如果传入的字符串中,每个字符如果第二个 byte 非 0,那么btoa 就会报错。

解决方案:

  1. MDN 中提到的方法是

    1
    2
    3
    4
    5
    6
    7
    8
    9
    // convert a Unicode string to a string in which
    // each 16-bit unit occupies only one byte
    function toBinary(string) {
    const codeUnits = new Uint16Array(string.length);
    for (let i = 0; i < codeUnits.length; i++) {
    codeUnits[i] = string.charCodeAt(i);
    }
    return String.fromCharCode(...new Uint8Array(codeUnits.buffer));
    }

    xxx = toBinary(‘你好’)

    得到的是

    1
    "`O}Y"

    再把这个字符串做 base64 编码,得到 YE99WQ==

    但是问题是解码后还需要通过函数转换才能得到原文

    1
    2
    3
    4
    5
    6
    7
    function fromBinary(binary) {
    const bytes = new Uint8Array(binary.length);
    for (let i = 0; i < bytes.length; i++) {
    bytes[i] = binary.charCodeAt(i);
    }
    return String.fromCharCode(...new Uint16Array(bytes.buffer));
    }
  2. 通过转义后再编码(参考

    1
    2
    3
    4
    5
    6
    7
    function utoa(str) {
    return window.btoa(unescape(encodeURIComponent(str)));
    }
    // base64 encoded ascii to ucs-2 string
    function atou(str) {
    return decodeURIComponent(escape(window.atob(str)));
    }

    utoa(‘你好’) 的结果是:5L2g5aW9

    好处是直接解码就得到原文,坏处是 unescape 方法已经不推荐使用了。

  3. 仅使用 encodeURIComponent 转义后再编码 (参考

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    function b64Encode(str) {
    return btoa(encodeURIComponent(str));
    }

    function b64Decode(str) {
    return decodeURIComponent(atob(str));
    }

    b64Encode('你好') // "JUU0JUJEJUEwJUU1JUE1JUJE"
    b64Decode('JUU0JUJEJUEwJUU1JUE1JUJE') // "你好"

    坏处是编码的结果变长,且解码后需要转义

评论无需登录,可以匿名,欢迎评论!