我得到了一个webSocket通讯,我接收到base64编码的字符串,将其转换为uint8并对其进行处理,但是现在我需要发送回去,我得到了uint8数组,并且需要将其转换为base64字符串,以便可以发送它。我该如何进行转换?
Answers:
已经提出的所有解决方案都存在严重问题。一些解决方案无法在大型阵列上运行,某些解决方案提供错误的输出,如果中间字符串包含多字节字符,则某些解决方案会在btoa调用上引发错误,有些解决方案会消耗比所需更多的内存。
因此,我实现了直接转换功能,该功能无论输入如何都可以正常工作。它在我的机器上每秒转换约500万个字节。
https://gist.github.com/enepomnyaschih/72c423f727d395eeaa09697058238727
"ABCDEFG..."
?
如果您的数据可能包含多字节序列(而不是纯ASCII序列),并且您的浏览器具有TextDecoder,则应使用该序列来解码数据(为TextDecoder指定所需的编码):
var u8 = new Uint8Array([65, 66, 67, 68]);
var decoder = new TextDecoder('utf8');
var b64encoded = btoa(decoder.decode(u8));
如果您需要支持没有TextDecoder的浏览器(当前只有IE和Edge),那么最好的选择是使用TextDecoder polyfill。
如果您的数据包含纯ASCII(不是多字节Unicode / UTF-8),那么有一个简单的替代方法String.fromCharCode
应该得到普遍支持:
var ascii = new Uint8Array([65, 66, 67, 68]);
var b64encoded = btoa(String.fromCharCode.apply(null, ascii));
并将base64字符串解码回Uint8Array:
var u8_2 = new Uint8Array(atob(b64encoded).split("").map(function(c) {
return c.charCodeAt(0); }));
如果您有非常大的数组缓冲区,则应用可能会失败,并且您可能需要对缓冲区进行分块(基于@RohitSengar发布的缓冲区)。再次注意,这仅在缓冲区仅包含非多字节ASCII字符时才是正确的:
function Uint8ToString(u8a){
var CHUNK_SZ = 0x8000;
var c = [];
for (var i=0; i < u8a.length; i+=CHUNK_SZ) {
c.push(String.fromCharCode.apply(null, u8a.subarray(i, i+CHUNK_SZ)));
}
return c.join("");
}
// Usage
var u8 = new Uint8Array([65, 66, 67, 68]);
var b64encoded = btoa(Uint8ToString(u8));
btoa(String.fromCharCode.apply(null, myArray))
Uint8Array
。TextDecoder
在这里使用绝对是错误的事情,因为如果您的Uint8Array
字节在128..255范围内,则文本解码器将错误地将其转换为Unicode字符,这将破坏base64转换器。
非常简单的解决方案和JavaScript测试!
ToBase64 = function (u8) {
return btoa(String.fromCharCode.apply(null, u8));
}
FromBase64 = function (str) {
return atob(str).split('').map(function (c) { return c.charCodeAt(0); });
}
var u8 = new Uint8Array(256);
for (var i = 0; i < 256; i++)
u8[i] = i;
var b64 = ToBase64(u8);
console.debug(b64);
console.debug(FromBase64(b64));
RangeError: Maximum call stack size exceeded
function Uint8ToBase64(u8Arr){
var CHUNK_SIZE = 0x8000; //arbitrary number
var index = 0;
var length = u8Arr.length;
var result = '';
var slice;
while (index < length) {
slice = u8Arr.subarray(index, Math.min(index + CHUNK_SIZE, length));
result += String.fromCharCode.apply(null, slice);
index += CHUNK_SIZE;
}
return btoa(result);
}
如果Uint8Array非常大,则可以使用此功能。这用于Javascript,在FileReader readAsArrayBuffer的情况下很有用。
String.fromCharCode.apply()
方法无法重现UTF-8:UTF-8字符的长度可能从一个字节到四个字节String.fromCharCode.apply()
不等,但会检查UInt8的分段中的UInt8Array,因此错误地假设每个字符长为一个字节,并且与相邻字符无关那些。如果输入UInt8Array中编码的字符都恰好在ASCII(单字节)范围内,则它会偶然起作用,但不能重现完整的UTF-8。您需要为此使用TextDecoder或类似的算法。
如果您使用的是Node.js,则可以使用此代码将Uint8Array转换为base64
var b64 = Buffer.from(u8).toString('base64');
这是一个JS函数:
之所以需要此功能,是因为Chrome在pushManager.subscribe中仍不接受base64编码的字符串作为applicationServerKey的值,而 https://bugs.chromium.org/p/chromium/issues/detail?id=802280
function urlBase64ToUint8Array(base64String) {
var padding = '='.repeat((4 - base64String.length % 4) % 4);
var base64 = (base64String + padding)
.replace(/\-/g, '+')
.replace(/_/g, '/');
var rawData = window.atob(base64);
var outputArray = new Uint8Array(rawData.length);
for (var i = 0; i < rawData.length; ++i) {
outputArray[i] = rawData.charCodeAt(i);
}
return outputArray;
}
(使用Unicode支持将Base64字符串解码为Uint8Array或ArrayBuffer)
Mozilla开发人员网络网站上显示了一种非常好的方法:
function btoaUTF16 (sString) {
var aUTF16CodeUnits = new Uint16Array(sString.length);
Array.prototype.forEach.call(aUTF16CodeUnits, function (el, idx, arr) { arr[idx] = sString.charCodeAt(idx); });
return btoa(String.fromCharCode.apply(null, new Uint8Array(aUTF16CodeUnits.buffer)));
}
function atobUTF16 (sBase64) {
var sBinaryString = atob(sBase64), aBinaryView = new Uint8Array(sBinaryString.length);
Array.prototype.forEach.call(aBinaryView, function (el, idx, arr) { arr[idx] = sBinaryString.charCodeAt(idx); });
return String.fromCharCode.apply(null, new Uint16Array(aBinaryView.buffer));
}
var myString = "☸☹☺☻☼☾☿";
var sUTF16Base64 = btoaUTF16(myString);
console.log(sUTF16Base64); // Shows "OCY5JjomOyY8Jj4mPyY="
var sDecodedString = atobUTF16(sUTF16Base64);
console.log(sDecodedString); // Shows "☸☹☺☻☼☾☿"
如果您想要的只是base64编码器的JS实现,以便可以将数据发送回去,则可以尝试使用该btoa
功能。
b64enc = btoa(uint);
关于btoa的几点快速注释-它是非标准的,因此不会强迫浏览器支持它。但是,大多数浏览器都可以。大人物,至少。atob
是相反的转换。
如果您需要其他实现,或者发现浏览器不知道您在说什么的极端情况,那么为JS搜索base64编码器就不会太困难。
由于某种原因,我认为其中有3个在我公司的网站上闲逛...
npm安装google-closure-library --save
require("google-closure-library");
goog.require('goog.crypt.base64');
var result =goog.crypt.base64.encodeByteArray(Uint8Array.of(1,83,27,99,102,66));
console.log(result);
$node index.js
将AVMbY2Y =写入控制台。
-ve
投票的答案被接受而不是一个高度的答案是很有趣的+ve
。