所以我将字符串转换为 BASE64,如下面的代码所示...
var str = "Hello World";
var enc = window.btoa(str);
这会产生
SGVsbG8gV29ybGQ=
。但是,如果我添加这些字符– ”
(例如下面所示的代码),则不会发生转换。这背后的原因是什么?非常感谢。
var str = "Hello – World”";
var enc = window.btoa(str);
btoa
是一个奇异的函数,因为需要一个“二进制字符串”,即它是一个 String
数据类型,但每个“字母”并不代表一个字母而是一个字节。因此,您不能有任何 Unicode 代码点高于 0xFF(字符代码 255)的“字母”,例如破折号和“花式”引号符号所使用的字符。
您必须首先对数据进行 uri 编码,以使其安全:
> var str = `Hello – World`;
> window.btoa(encodeURIComponent(str));
"SGVsbG8lMjAlRTIlODAlOTMlMjBXb3JsZA=="
然后自己拆包的时候记得再次解码:
> var base64= "SGVsbG8lMjAlRTIlODAlOTMlMjBXb3JsZA==";
> decodeURIComponent(window.atob(base64));
"Hello – World"
或者依赖自动应用 URI 解码的目标,如
href
属性(a
、link
等)。
但是,如果您的目标没有(您自己的代码,或
src
、img
上的 script
属性等),那么您需要将字符串转换为符合单字节打包的新字符串。 base64 的 MDN 上明确指出了这一点,他们的解决方案是:
function base64(data) {
const bytes = new TextEncoder().encode(data);
const binString = String.fromCodePoint(...bytes);
return btoa(binString);
}
function decode64(base64) {
const binString = atob(base64);
const bytes = Uint8Array.from(binString, (m) => m.codePointAt(0));
return new TextDecoder().decode(bytes);
}
如果您想在自己的代码中解压内容,则需要
decode64
,但是 base64
函数将生成一个转换后的字符串,该字符串在放入数据 URL 时将起作用(例如 data:text/javascript;base64,${base64text}
);
问题是字符
”
位于 Latin1 范围之外。
为此,您可以使用
unescape
(现已弃用)
var str = "Hello – World”";
var enc = btoa(unescape(encodeURIComponent(str)));
alert(enc);
并解码:
var encStr = "SGVsbG8g4oCTIFdvcmxk4oCd";
var dec = decodeURIComponent(escape(window.atob(encStr)))
alert(dec);
这最终是由于 JavaScript 类型系统的缺陷。
JavaScript 字符串是 16 位代码单元的字符串,通常被解释为 UTF-16。 Base64 编码是一种将 8 位 字节流转换为数字字符串的方法,方法是将每三个字节映射为四个数字,每个数字覆盖 6 位:3 × 8 = 4 × 6。正如我们所见,这很大程度上取决于每个符号的位宽度。
在定义
btoa
函数时,JavaScript 没有 8 位字节流的类型,因此 API 被定义为采用普通的 16 位字符串类型作为输入,限制是每个代码单元应该限制在[U+0000, U+00FF]范围内;当编码为 ISO-8859-1 时,这样的字符串将准确地再现预期的字节流。
字符
–
是U+2013,而”
是U+201D;这些字符都不符合上述范围,因此该函数拒绝它。
如果要将 Unicode 文本转换为 Base64,则需要先选择一种字符编码并将其转换为字节字符串,然后对 that 进行编码。要求 Unicode 字符串本身的 Base64 编码是没有意义的。
最可靠的方法是直接处理二进制数据。
为此,您可以将字符串编码为表示字符串的 UTF-8 版本的
ArrayBuffer
对象。
然后
FileReader
实例将能够很容易地为您提供base64。
var str = "Hello – World”";
var buf = new TextEncoder().encode( str );
var reader = new FileReader();
reader.onload = evt => { console.log( reader.result.split(',')[1] ); };
reader.readAsDataURL( new Blob([buf]) );
而且由于
Blob()
构造函数会自动将 DOMString
实例编码为 UTF-8,我们甚至可以删除 TextEncoder
对象:
var str = "Hello – World”";
var reader = new FileReader();
reader.onload = evt => { console.log( reader.result.split(',')[1] ); };
reader.readAsDataURL( new Blob([str]) );