01月16日
解决 Javascript 中 atob 方法解码中文字符乱码问题

由于一些网络通讯协议的限制,你必须使用 window.btoa() 方法对原数据进行编码后,才能进行发送。接收方使用相当于 window.atob() 的方法对接受到的 base64 数据进行解码,得到原数据。例如,发送某些含有 ASCII 码表中 0 到 31 之间的控制字符的数据。

window.btoawindow.atob 不支持中文

对于 unicode 编码的字符进行 base64 编码之后,通过浏览器原生的 btoa 方法界面中文会乱码。

在 bash 终端,将“中文”转成 base64 编码

$ echo 中文 | base64
5Lit5paHCg==

在 Chrome console 通过 window.atob 解码,结果为乱码

> window.atob('5Lit5paHCg==')
中文

在 Chrome console 中执行 windows.btoa 编码,报错

> window.btoa('中文')
Uncaught DOMException: Failed to execute 'btoa' on 'Window': The string to be encoded contains characters outside of the Latin1 range.

从错误提示看, btoa 仅支持 ASCII 编码。

借助 encodeURIComponentdecodeURIComponent 转义非中文字符

由于 btoa 仅支持 ASCII 字符序列,如果通过 encodeURIComponent 将中文字符编码成ASCII字符序列,再通过 btoa 进行 base64 编码。

编码

> window.btoa(encodeURIComponent('中文'))
"JUU0JUI4JUFEJUU2JTk2JTg3"

解码

> decodeURIComponent(window.atob('JUU0JUI4JUFEJUU2JTk2JTg3'))
"中文"

虽然到达了曲线救国的目的,但是由于 encodeURIComponentdecodeURIComponent 已经达到了转义控制字符的目的,使用 atobbtoa 感觉是多此一举。

第三方 Base64 工具

webtoolkit.base64是一个第三方实现的 Base64 编码工具,完美的支持 unicode 编码的字符串。

> Base64.encode('中文')
"5Lit5paH"

> Base64.decode('5Lit5paH');
"中文"

另外,如果服务端为 Nodejs ,可用如下 coffee 代码进行 base64 的编码和解码。

btoa: (s)->
    (new Buffer(s, 'utf8')).toString('base64')
atob: (s)->
    (new Buffer(s, 'base64').toString('utf8'))

参考阅读

  1. btoa(), atob() 支援中文的方法
  2. How to encode UTF8 characters into Base64 in JavaScript
  3. window.atob
  4. Best practice: escape, or encodeURI / encodeURIComponent

Vangie Du

将来的你,一定会感谢现在拼命努力的自己!

杜万1881515

15条评论

用到了,不错。

rgqancy2 年前回复

猴赛雷

digo4 年前回复
unescape并非多次一举,我在编码svg的时候,不加unescape编码会失败,不能正确的放到img里面。 btw:评论这验证码太坑,防御垃圾评论,也防御了想留言的心。坑了3个小时的.toDataURL()问题心情大好,谢谢@水中月明
匿名4 年前回复
unescape并非多次一举,我在编码svg的时候,不加unescape编码会失败,不能正确的放到img里面。 btw:评论这验证码太坑,防御垃圾评论,也防御了想留言的心。坑了3个小时的.toDataURL()问题心情大好,谢谢@水中月明
匿名4 年前回复
unescape并非多次一举,我在编码svg的时候,不加unescape编码会失败,不能正确的放到img里面。 btw:评论这验证码太坑,防御垃圾评论,也防御了想留言的心。坑了3个小时的.toDataURL()问题心情大好,谢谢@水中月明
匿名4 年前回复
unescape并非多次一举,我在编码svg的时候,不加unescape编码会失败,不能正确的放到img里面。 btw:评论这验证码太坑,防御垃圾评论,也防御了想留言的心。坑了3个小时的.toDataURL()问题心情大好,谢谢@水中月明
匿名4 年前回复
unescape并非多次一举,我在编码svg的时候,不加unescape编码会失败,不能正确的放到img里面。 btw:评论这验证码太坑,防御垃圾评论,也防御了想留言的心。坑了3个小时的.toDataURL()问题心情大好,谢谢@水中月明
匿名4 年前回复
unescape并非多次一举,我在编码svg的时候,不加unescape编码会失败,不能正确的放到img里面。 btw:评论这验证码太坑,防御垃圾评论,也防御了想留言的心。坑了3个小时的.toDataURL()问题心情大好,谢谢@水中月明
匿名4 年前回复
unescape并非多次一举,我在编码svg的时候,不加unescape编码会失败,不能正确的放到img里面。 btw:评论这验证码太坑,防御垃圾评论,也防御了想留言的心。坑了3个小时的.toDataURL()问题心情大好,谢谢@水中月明
匿名4 年前回复
unescape并非多次一举,我在编码svg的时候,不加unescape编码会失败,不能正确的放到img里面。 btw:评论这验证码太坑,防御垃圾评论,也防御了想留言的心。坑了3个小时的.toDataURL()问题心情大好,谢谢@水中月明
匿名4 年前回复