客户端Javascript中的Base64编码和解码

JavaScript中是否有任何方法可以用来编码和解码使用base64编码的字符串?

919096 次浏览

一些浏览器,如Firefox, Chrome, Safari, Opera和IE10+可以原生处理Base64。看一下这个Stackoverflow问题。它正在使用__ABC0和atob()函数

对于服务器端JavaScript (Node),可以使用Buffers进行解码。

如果你想要一个跨浏览器的解决方案,有像CryptoJS这样的现有库或如下代码:

http://ntt.cc/2008/01/19/base64-encoder-decoder-with-javascript.html (存档)

对于后者,您需要彻底测试该函数的跨浏览器兼容性。和错误已经有报道了

php.js项目有很多PHP函数的JavaScript实现。包括base64_encodebase64_decode

短而快速的Base64 JavaScript解码函数没有Failsafe:

function decode_base64 (s)
{
var e = {}, i, k, v = [], r = '', w = String.fromCharCode;
var n = [[65, 91], [97, 123], [48, 58], [43, 44], [47, 48]];


for (z in n)
{
for (i = n[z][0]; i < n[z][1]; i++)
{
v.push(w(i));
}
}
for (i = 0; i < 64; i++)
{
e[v[i]] = i;
}


for (i = 0; i < s.length; i+=72)
{
var b = 0, c, x, l = 0, o = s.substring(i, i+72);
for (x = 0; x < o.length; x++)
{
c = e[o.charAt(x)];
b = (b << 6) + c;
l += 6;
while (l >= 8)
{
r += w((b >>> (l -= 8)) % 256);
}
}
}
return r;
}

在基于Gecko/ webkit的浏览器(Firefox、Chrome和Safari)和Opera中,可以使用btoa ()atob ()

原来的答案:如何在JavaScript中将字符串编码为Base64 ?

我已经尝试了phpjs.org的Javascript例程,他们工作得很好。

我首先尝试了Ranhiru Cooray选择的答案中建议的套路——http://ntt.cc/2008/01/19/base64-encoder-decoder-with-javascript.html

我发现它们并不是在所有情况下都有效。我写了一个测试用例,这些例程失败了,并将它们发布到GitHub:

https://github.com/scottcarter/base64_javascript_test_data.git

我也在ntt的博客上发表了评论。抄送提醒作者(等待审核-文章是旧的,所以不确定是否会张贴评论)。

以下是Sniper的文章的压缩版。它假定格式良好的base64字符串,没有回车。这个版本消除了几个循环,从Yaroslav中添加了&0xff修复,消除了尾随null,再加上一些代码golf。

decodeBase64 = function(s) {
var e={},i,b=0,c,x,l=0,a,r='',w=String.fromCharCode,L=s.length;
var A="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
for(i=0;i<64;i++){e[A.charAt(i)]=i;}
for(x=0;x<L;x++){
c=e[s.charAt(x)];b=(b<<6)+c;l+=6;
while(l>=8){((a=(b>>>(l-=8))&0xff)||(x<(L-2)))&&(r+=w(a));}
}
return r;
};

我宁愿使用CryptoJS中的bas64编码/解码方法,这是使用最佳实践和模式在JavaScript中实现的最流行的标准和安全加密算法库。

有人说code golf吗?=)

以下是我在跟上时代的同时提高我的障碍的尝试。提供给你方便。

function decode_base64(s) {
var b=l=0, r='',
m='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
s.split('').forEach(function (v) {
b=(b<<6)+m.indexOf(v); l+=6;
if (l>=8) r+=String.fromCharCode((b>>>(l-=8))&0xff);
});
return r;
}

我真正追求的是一个异步实现,令我惊讶的是,与JQuery的$([]).each方法实现相比,forEach方法实现是非常同步的。

如果你也有这样疯狂的想法,0延迟window.setTimeout将异步运行base64解码,并在完成时执行回调函数的结果。

function decode_base64_async(s, cb) {
setTimeout(function () { cb(decode_base64(s)); }, 0);
}

@ brush建议“像数组一样索引字符串”,并去掉split。这个例行公事似乎真的很奇怪,不确定如何兼容它将,但它确实击中另一个小鸟,所以让我们有它。

function decode_base64(s) {
var b=l=0, r='',
m='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
[].forEach.call(s, function (v) {
b=(b<<6)+m.indexOf(v); l+=6;
if (l>=8) r+=String.fromCharCode((b>>>(l-=8))&0xff);
});
return r;
}

在试图找到更多关于JavaScript字符串作为数组的信息时,我无意中发现了这个专业技巧,使用/./g正则表达式来逐级遍历字符串。通过替换字符串并消除保留返回变量的需要,这进一步减少了代码大小。

function decode_base64(s) {
var b=l=0,
m='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
return s.replace(/./g, function (v) {
b=(b<<6)+m.indexOf(v); l+=6;
return l<8?'':String.fromCharCode((b>>>(l-=8))&0xff);
});
}

然而,如果你正在寻找一些更传统的东西,也许下面的更符合你的口味。

function decode_base64(s) {
var b=l=0, r='', s=s.split(''), i,
m='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
for (i in s) {
b=(b<<6)+m.indexOf(s[i]); l+=6;
if (l>=8) r+=String.fromCharCode((b>>>(l-=8))&0xff);
}
return r;
}

我没有后面的空问题,所以这被删除了,以保持低于标准,但它应该很容易地用trim()trimRight()解决,如果你愿意,这应该给你带来一个问题。

ie。

return r.trimRight();

注意:

结果是一个ascii字节字符串,如果你需要unicode,最简单的方法是escape字节字符串,然后可以用decodeURIComponent解码以产生unicode字符串。

function decode_base64_usc(s) {
return decodeURIComponent(escape(decode_base64(s)));
}

由于escape已弃用,我们可以将函数改为直接支持unicode,而不需要escapeString.fromCharCode,我们可以生成一个%转义字符串,以便URI解码。

function decode_base64(s) {
var b=l=0,
m='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
return decodeURIComponent(s.replace(/./g, function (v) {
b=(b<<6)+m.indexOf(v); l+=6;
return l<8?'':'%'+(0x100+((b>>>(l-=8))&0xff)).toString(16).slice(-2);
}));
}

编辑@Charles Byrne:

不记得为什么我们没有忽略'='填充字符,可能是在当时不需要它们的规范下工作的。如果我们修改decodeURIComponent例程来忽略这些,因为它们不代表任何数据,结果将正确解码示例。

function decode_base64(s) {
var b=l=0,
m='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
return decodeURIComponent(s.replace(/=*$/,'').replace(/./g, function (v) {
b=(b<<6)+m.indexOf(v); l+=6;
return l<8?'':'%'+(0x100+((b>>>(l-=8))&0xff)).toString(16).slice(-2);
}));
}

现在调用decode_base64('4pyTIMOgIGxhIG1vZGU=')将返回编码后的字符串'✓ à la mode',没有任何错误。

因为'='被保留为填充字符,我可以减少我的代码高尔夫差点,如果我可以:

function decode_base64(s) {
var b=l=0,
m='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
return decodeURIComponent(s.replace(/./g, function (v) {
b=(b<<6)+m.indexOf(v); l+=6;
return l<8||'='==v?'':'%'+(0x100+((b>>>(l-=8))&0xff)).toString(16).slice(-2);
}));
}

nJoy !

Internet Explorer 10+

// Define the string
var string = 'Hello World!';


// Encode the String
var encodedString = btoa(string);
console.log(encodedString); // Outputs: "SGVsbG8gV29ybGQh"


// Decode the String
var decodedString = atob(encodedString);
console.log(decodedString); // Outputs: "Hello World!"

跨浏览器

为AMD, CommonJS, Nodejs和浏览器重写和模块化的UTF-8和Base64 Javascript编码和解码库/模块。跨浏览器兼容的。< / >


用node . js

下面是在Node.js中如何将普通文本编码为base64:

//Buffer() requires a number, array or string as the first parameter, and an optional encoding type as the second parameter.
// Default is utf8, possible encoding types are ascii, utf8, ucs2, base64, binary, and hex
var b = Buffer.from('JavaScript');
// If we don't use toString(), JavaScript assumes we want to convert the object to utf8.
// We can make it convert to other formats by passing the encoding type to toString().
var s = b.toString('base64');

下面是解码base64编码字符串的方法:

var b = Buffer.from('SmF2YVNjcmlwdA==', 'base64')
var s = b.toString();

. js和

使用dojox.encoding.base64对字节数组进行编码:

var str = dojox.encoding.base64.encode(myByteArray);

解码base64编码的字符串:

var bytes = dojox.encoding.base64.decode(str)

安装angular-base64

<script src="bower_components/angular-base64/angular-base64.js"></script>


angular
.module('myApp', ['base64'])
.controller('myController', [


'$base64', '$scope',
function($base64, $scope) {
    

$scope.encoded = $base64.encode('a string');
$scope.decoded = $base64.decode('YSBzdHJpbmc=');
}]);

但如何?

如果你想了解更多关于base64是如何编码的,特别是在JavaScript中,我推荐这篇文章:JavaScript计算机科学:Base64编码

function b64_to_utf8( str ) {
return decodeURIComponent(escape(window.atob( str )));
}

https://developer.mozilla.org/en-US/docs/Web/API/WindowBase64/Base64_encoding_and_decoding#The_.22Unicode_Problem.22

在Node.js中,我们可以用简单的方式做到这一点

var base64 = 'SGVsbG8gV29ybGQ='
var base64_decode = new Buffer(base64, 'base64').toString('ascii');


console.log(base64_decode); // "Hello World"

对于没有atob方法的JavaScripts框架,如果你不想导入外部库,这是一个简短的函数。

它将获得一个包含Base64编码值的字符串,并将返回一个解码后的字节数组(其中字节数组表示为数字数组,其中每个数字都是0到255之间的整数)。

function fromBase64String(str) {
var alpha =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
var value = [];
var index = 0;
var destIndex  = 0;
var padding = false;
while (true) {


var first  = getNextChr(str, index, padding, alpha);
var second = getNextChr(str, first .nextIndex, first .padding, alpha);
var third  = getNextChr(str, second.nextIndex, second.padding, alpha);
var fourth = getNextChr(str, third .nextIndex, third .padding, alpha);


index = fourth.nextIndex;
padding = fourth.padding;


// ffffffss sssstttt ttffffff
var base64_first  = first.code  == null ? 0 : first.code;
var base64_second = second.code == null ? 0 : second.code;
var base64_third  = third.code  == null ? 0 : third.code;
var base64_fourth = fourth.code == null ? 0 : fourth.code;


var a = (( base64_first << 2) & 0xFC ) | ((base64_second>>4) & 0x03);
var b = (( base64_second<< 4) & 0xF0 ) | ((base64_third >>2) & 0x0F);
var c = (( base64_third << 6) & 0xC0 ) | ((base64_fourth>>0) & 0x3F);


value [destIndex++] = a;
if (!third.padding) {
value [destIndex++] = b;
} else {
break;
}
if (!fourth.padding) {
value [destIndex++] = c;
} else {
break;
}
if (index >= str.length) {
break;
}
}
return value;
}


function getNextChr(str, index, equalSignReceived, alpha) {
var chr = null;
var code = 0;
var padding = equalSignReceived;
while (index < str.length) {
chr = str.charAt(index);
if (chr == " " || chr == "\r" || chr == "\n" || chr == "\t") {
index++;
continue;
}
if (chr == "=") {
padding = true;
} else {
if (equalSignReceived) {
throw new Error("Invalid Base64 Endcoding character \""
+ chr + "\" with code " + str.charCodeAt(index)
+ " on position " + index
+ " received afer an equal sign (=) padding "
+ "character has already been received. "
+ "The equal sign padding character is the only "
+ "possible padding character at the end.");
}
code = alpha.indexOf(chr);
if (code == -1) {
throw new Error("Invalid Base64 Encoding character \""
+ chr + "\" with code " + str.charCodeAt(index)
+ " on position " + index + ".");
}
}
break;
}
return { character: chr, code: code, padding: padding, nextIndex: ++index};
}

使用的资源:RFC-4648

不管怎样,我从其他答案中得到了启发,写了一个小实用程序,调用特定于平台的api,从Node.js或浏览器中普遍使用:

/**
* Encode a string of text as base64
*
* @param data The string of text.
* @returns The base64 encoded string.
*/
function encodeBase64(data: string) {
if (typeof btoa === "function") {
return btoa(data);
} else if (typeof Buffer === "function") {
return Buffer.from(data, "utf-8").toString("base64");
} else {
throw new Error("Failed to determine the platform specific encoder");
}
}


/**
* Decode a string of base64 as text
*
* @param data The string of base64 encoded text
* @returns The decoded text.
*/
function decodeBase64(data: string) {
if (typeof atob === "function") {
return atob(data);
} else if (typeof Buffer === "function") {
return Buffer.from(data, "base64").toString("utf-8");
} else {
throw new Error("Failed to determine the platform specific decoder");
}
}

现代浏览器有内置的javascript函数,用于Base64编码btoa ()和解码atob ()。有关旧浏览器版本支持的更多信息:https://caniuse.com/?search=atob

但是,要注意atobbtoa函数仅适用于ASCII字符集。 如果你需要Base64函数的UTF-8字符集,你可以这样做:

function base64_encode(s) {
return btoa(unescape(encodeURIComponent(s)));
}
function base64_decode(s) {
return decodeURIComponent(escape(atob(s)));
}

Base64 赢得- 1251解码用于编码除了acsi或iso-8859-1。

结果,我在这里看到的所有脚本都将西里尔Base64转换为iso-8859-1编码。奇怪的是没有人注意到这一点。

因此,要恢复西里尔字母,只需将文本从iso-8859-1转换为windows-1251即可。

我认为其他语言也是如此。只要把Cyrilic window -1251改成你的。

…感谢Der Hochstapler的代码,我从他的评论中了解到…过度评论,这有点不寻常。

JScript代码(仅适用于Windows桌面)(ActiveXObject) - 1251文件编码

decode_base64=function(f){var g={},b=65,d=0,a,c=0,h,e="",k=String.fromCharCode,l=f.length;for(a="";91>b;)a+=k(b++);a+=a.toLowerCase()+"0123456789+/";for(b=0;64>b;b++)g[a.charAt(b)]=b;for(a=0;a<l;a++)for(b=g[f.charAt(a)],d=(d<<6)+b,c+=6;8<=c;)((h=d>>>(c-=8)&255)||a<l-2)&&(e+=k(h));return e};
sDOS2Win = function(sText, bInsideOut) {
var aCharsets = ["iso-8859-1", "windows-1251"];
sText += "";
bInsideOut = bInsideOut ? 1 : 0;
with (new ActiveXObject("ADODB.Stream")) { //http://www.w3schools.com/ado/ado_ref_stream.asp
type = 2; //Binary 1, Text 2 (default)
mode = 3; //Permissions have not been set 0,  Read-only 1,  Write-only 2,  Read-write 3,
//Prevent other read 4,  Prevent other write 8,  Prevent other open 12,  Allow others all 16
charset = aCharsets[bInsideOut];
open();
writeText(sText);
position = 0;
charset = aCharsets[1 - bInsideOut];
return readText();
}
}
var base64='0PPx8ero5SDh8+ru4uroIQ=='
text = sDOS2Win(decode_base64(base64), false );
WScript.Echo(text)
var x=WScript.StdIn.ReadLine();

前端:上面的解决方案很好,但后端很快……

NodeJS -不弃用

使用Buffer.from

> inBase64 = Buffer.from('plain').toString('base64')
'cGxhaW4='


> // DEPRECATED //
> new Buffer(inBase64, 'base64').toString()
'plain'
> (node:1188987) [DEP0005] DeprecationWarning: Buffer() is deprecated due to security and usability issues. Please use the Buffer.alloc(), Buffer.allocUnsafe(), or Buffer.from() methods instead.
(Use `node --trace-deprecation ...` to show where the warning was created)


// Works //
> Buffer.from(inBase64, 'base64').toString()
'plain'