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


Answers:


213

某些浏览器(例如Firefox,Chrome,Safari,Opera和IE10 +)可以原生处理Base64。看一下这个Stackoverflow问题。它的使用btoa()atob()功能

对于服务器端JavaScript(节点),您可以使用 Buffer进行解码。

如果您要使用跨浏览器解决方案,则可以使用现有的库,例如CryptoJS或类似以下的代码:

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

对于后者,您需要彻底测试该功能是否具有跨浏览器兼容性。并且错误已经被报告


1
我使用此方法使用Date URI方案在base64中编码SVG。惊喜:此函数对每个字符进行urlencode编码,因此我得到了目标格式不正确的XML:%3C%3Fxml%20version%3D%271.0%27%20%3F%3E%3Csvg%20xmlns%3D%27http%...
Dereckson

21
Node.js可以本地执行Base64 :(new Buffer('Hello, world!').toString('base64'); new Buffer('SGVsbG8sIHdvcmxkIQ==', 'base64').toString('ascii'); 源)
nyuszika7h 2014年

如果我想做到网址安全?
anddero

1
在节点5+中,不建议使用Buffer.from new Buffer(string)Buffer.from(jwt.split('.')[1], 'base64').toString()
雷·福斯

63

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

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


这可以节省生命。我使用了几种不同的实现来解码非常大的base64编码的字符串,结果始终是错误的。atob()很棒!
b2238488'8

15
小问题:Opera不是基于Gecko或Webkit,而是使用自己的渲染引擎Presto。
彼得·奥尔森

哇,谢谢你 不知道这些浏览器中有本机的base64编码器!
Rob Porter 2012年

5
@PeterOlson不再:)
Mustafa

1
我意识到这是一篇老文章,但是关于@ b2238488的关注,您可以拆分base64字符串,以便每个令牌的长度为4的倍数,然后分别对其进行解码。结果将与立即解码整个字符串相同。
nyuszika7h 2013年

56

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 Java编码和解码库/模块进行了重新编写和模块化。跨浏览器兼容。


与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 = new Buffer('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 = new Buffer('SmF2YVNjcmlwdA==', 'base64')
var s = b.toString();

与Dojo.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=');
}]);

但是如何?

如果您想了解有关一般如何以及特别是JavaScript编码的更多信息,我建议您阅读本文: JavaScript中的计算机科学:Base64编码


1
FYI:跨浏览器的版本有一些讨厌的泄漏与c2和可能c1,并c3因此它不会与工作"use strict"上面定义。
Campbeln'1

41

这是狙击手的收紧版本。假定格式良好的base64字符串没有回车符。这个版本消除了几个循环,添加了&0xffYaroslav 的修复程序,消除了尾随的null,以及一些代码优化。

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;
};

5
更少的字节; DdecodeBase64=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};
Der Hochstapler,2015年

是的,但仅适用于ASCII。例如,西尔字符被弄乱了。
马丁·科瓦切夫

@MartinKovachev您可以使用Cyr字符和相应的base64编码发布带有示例文本的新评论吗?也许我们可以修复代码以适应。
broc.seib

在这里:类似的内容:тестовафраза–
Martin Kovachev

2
@OliverSalzburg甚至更少生成代码表:):var g={},k=String.fromCharCode,i;for(i=0;i<64;)g[k(i>61?(i&1)*4|43:i+[65,71,-4][i/26&3])]=i++;
Mike

34

简短而快速的Base64 JavaScript解码功能,无故障保护:

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;
}

6
Opera 11.62似乎在'%256'部分存在问题。用'&0xff'替换它可以正常工作。
Yaroslav Stavnichiy'5

Tyk虚拟终结点javascript代码似乎在'\ x00'部分存在问题。用r = r.replace(/ \ x00 / g,'')替换它可以正常工作
Panupong Kongarn


11

php.js项目有很多的PHP的功能的JavaScript实现。base64_encode并且base64_decode包括在内。


php.js是万恶的化身,属于地狱中自己的一层。避免像瘟疫一样。(更多信息:softwareengineering.stackexchange.com/questions/126671/…
Coreus,

在该链接@Coreus中,我看不出有多少支持该总体主张的。明智地使用或作为起点,这是一种完全可以接受的方法,可以弄清JS中可能已经知道如何在PHP中完成的工作中的等效逻辑。
ceejayoz

8

有人说打高尔夫球吗?=)

以下是我在与时俱进的过程中改善自己的障碍的尝试。为您提供方便。

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;
}

我实际上所追求的是一个异步实现,但令我惊讶的是,事实证明forEach与JQuery的$([]).each方法实现相反,它是非常同步的。

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

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

@Toothbrush建议“像数组一样对字符串进行索引”,然后删除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;
}

我没有尾随的null问题,因此将其删除以保持在标准水平以下,但应使用a trim()或a 轻松解决trimRight()如果您愿意,如果这对您造成了问题。

即。

return r.trimRight();

注意:

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

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

以来 escape不推荐使用,我们可以更改功能以直接支持unicode,而无需这样做,escape或者String.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);
  }));
}

欢乐!


3
您不需要split字符串,因为您可以像数组一样索引JavaScript字符串。s.split('').forEach(function ...可以替换为[].forEach.call(s, function ...。由于不必拆分字符串,因此它应该快得多。
牙刷

对于我来说,“更传统的”完全被打破了-产生乱七八糟的局面,并散布着原始文字的痕迹。在Chrome上。
史蒂夫·本内特

@Steve Bennett我测试了chrome的所有变体...有效。您能否提供失败的示例base64字符串?
尼克

三年后?哈。我什至不记得我需要什么。
史蒂夫·贝内特

6

我已经在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.cc的博客上发布了评论,以提醒作者(正在等待审核-该文章很旧,所以不确定是否会发表评论)。


1

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


1

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

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

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

0

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

它将获得一个包含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第4节

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.