Codificação e decodificação Base64 em Javascript do lado do cliente


Respostas:


214

Alguns navegadores como Firefox, Chrome, Safari, Opera e IE10 + podem lidar com o Base64 nativamente. Dê uma olhada nesta pergunta do Stackoverflow . Está usando btoa()e atob()funções .

Para JavaScript do lado do servidor (Nó), você pode usar Buffers para decodificar.

Se você está procurando uma solução entre navegadores, existem bibliotecas existentes como o CryptoJS ou código como:

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

Com o último, você precisa testar minuciosamente a função para compatibilidade entre navegadores. E o erro já foi relatado .


1
Eu usei esse método para codificar um SVG na base64 com o esquema URI da data. Surpresa: essa função codifica cada caractere, para obter o XML malformado no destino:% 3C% 3Fxml% 20version% 3D% 271,0% 27% 20% 3F% 3E% 3Csvg% 20xmlns% 3D% 27http% ...
— Dereckson

21
Node.js pode fazer Base64 nativamente: new Buffer('Hello, world!').toString('base64'); new Buffer('SGVsbG8sIHdvcmxkIQ==', 'base64').toString('ascii'); (fonte)
— nyuszika7h

E se eu quisesse fazê-lo com URL seguro?
— anddero 18/09/19

1
no nó 5+, use Buffer.from, pois new Buffer(string)está obsoleto. Buffer.from(jwt.split('.')[1], 'base64').toString()
— Ray Foss

63

Nos navegadores baseados no Gecko / WebKit (Firefox, Chrome e Safari) e no Opera, você pode usar btoa () e atob () .

Resposta original: Como você pode codificar uma string para Base64 em JavaScript?


Este é um salva-vidas. Usei algumas implementações diferentes para decodificar cadeias muito grandes codificadas em base64 e o resultado sempre estava errado. atob () funciona muito bem!
— 2222848

15
Nitpick pequeno: o Opera não é baseado no Gecko ou no Webkit, ele usa seu próprio mecanismo de renderização chamado Presto.
— 31812 Peter Olson

Uau, obrigado por isso. Não sabia que havia um codificador base64 nativo nesses navegadores!
— Rob Porter

5
@PeterOlson Not anymore :)
— Mustafa

1
Sei que essa é uma postagem antiga, mas sobre a preocupação de @ b2238488, você pode dividir a sequência base64 para que o comprimento de cada token seja um múltiplo de 4 e decodificá-los separadamente. O resultado será o mesmo que decodificar a sequência inteira de uma só vez.
— usar o seguinte código

56

Internet Explorer 10 ou superior

// 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!"

Navegador Cruzado

Bibliotecas / módulos de codificação e decodificação UTF-8 e Base64 Javascript reescritos e modularizados para AMD, CommonJS, Nodejs e navegadores. Compatível com vários navegadores.


com Node.js

Aqui está como você codifica o texto normal para base64 no Node.js:

//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');

E aqui está como você decodifica cadeias codificadas em base64:

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

com Dojo.js

Para codificar uma matriz de bytes usando dojox.encoding.base64:

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

Para decodificar uma sequência codificada em base64:

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

bower install 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=');
}]);

Mas como?

Se você quiser saber mais sobre como a base64 é codificada em geral e em JavaScript em particular, eu recomendaria este artigo: Ciência da computação em JavaScript: codificação Base64


1
FYI: A versão cross-browser tem alguns vazamentos desagradáveis com c2e provável c1e c3por isso não irá trabalhar com "use strict"como definido acima.
— Campbeln

41

Aqui está uma versão mais rigorosa do post de Sniper. Ele pressupõe uma string base64 bem formada, sem retornos de carro. Esta versão elimina alguns loops, adiciona a &0xffcorreção de Yaroslav, elimina valores nulos à direita, além de um pouco de código de golfe.

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
Ainda menos bytes; 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

Sim, mas funciona apenas com ASCII. Os personagens Cyr são mutilados, por exemplo.
— Martin Kovachev

@MartinKovachev, você pode postar um novo comentário com texto de exemplo com caracteres Cyr e a codificação base64 correspondente? Talvez possamos corrigir o código para acomodar.
— Broc.seib 17/09/2015

Aqui: algo assim: фраза тестова
— Martin Kovachev

2
@OliverSalzburg Menos ainda gera tabela de códigos :):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

Função de decodificação de JavaScript Base64 curta e rápida, sem falhas:

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
O Opera 11.62 parece ter problema com a parte '% 256'. Substituí-lo por '& 0xff' faz com que funcione.
— Yaroslav Stavnichiy

O código javascript do terminal virtual Tyk parece ter um problema com a parte '\ x00'. Substituí-lo por r = r.replace (/ \ x00 / g, '') faz com que funcione
— Panupong Kongarn 14/02


11

O projeto php.js possui implementações em JavaScript de muitas das funções do PHP. base64_encodee base64_decodeestão incluídos.


O php.js é a encarnação de todo o mal e pertence à sua própria camada no inferno. Evite como uma praga. (Mais informações: softwareengineering.stackexchange.com/questions/126671/… )
— Coreus 03/04/19

Não vejo muito apoio a essa afirmação geral nesse link, @Coreus. Usada criteriosamente, ou como ponto de partida, é uma maneira perfeitamente aceitável de descobrir a lógica equivalente em JS para algo que você já deve saber fazer em PHP.
— ceejayoz

9

Alguém disse código de golfe? =)

A seguir, é minha tentativa de melhorar minha desvantagem enquanto acompanho os horários. Fornecido para sua conveniência.

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

Na verdade, o que eu procurava era uma implementação assíncrona e, para minha surpresa, ao forEachcontrário da $([]).eachimplementação do método JQuery, é muito síncrona.

Se você também tiver em mente essas noções malucas, um atraso 0 window.setTimeoutexecutará a decodificação da base64 de forma assíncrona e executará a função de retorno de chamada com o resultado quando terminar.

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

A @ Toothbrush sugeriu "indexar uma string como uma matriz" e se livrar do split. Essa rotina parece realmente estranha e não tem certeza de quão compatível será, mas atinge outro passarinho, então vamos lá.

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

Ao tentar encontrar mais informações sobre a string JavaScript como array, eu tropecei nesta dica profissional usando um /./gregex para percorrer uma string. Isso reduz ainda mais o tamanho do código, substituindo a string no lugar e eliminando a necessidade de manter uma variável de retorno.

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

Se, no entanto, você estava procurando algo um pouco mais tradicional, talvez o seguinte seja mais para o seu gosto.

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

Como não havia o problema nulo à direita, ele foi removido para permanecer abaixo do padrão, mas deve ser facilmente resolvido com um trim()ou umtrimRight() se você preferir, caso isso represente um problema para você.

ie

return r.trimRight();

Nota:

O resultado é uma sequência de bytes ascii, se você precisar de unicode, o mais fácil é a escapesequência de bytes que pode ser decodificada decodeURIComponentpara produzir a sequência de caracteres unicode.

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

Como escapeestá sendo descontinuado, podemos alterar nossa função para oferecer suporte a unicode diretamente sem a necessidade escapeou String.fromCharCodepodemos produzir uma %string de escape pronta para decodificação de 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);
  }));
}

nJoy!


3
Você não precisa splitda string, pois pode indexar uma string JavaScript como uma matriz. s.split('').forEach(function ...pode ser substituído por [].forEach.call(s, function .... Deve ser muito mais rápido, porque não é necessário dividir a string.
— Escova de dentes

O "mais tradicional" foi completamente quebrado para mim - produziu uma bagunça ilegível com traços de texto original espalhados por toda parte. No Chrome.
— Steve Bennett

@ Steve Bennett Eu testei todas as variantes no chrome ... funciona. Você pode fornecer um exemplo de string base64 que falha?
— nickl-

Três anos depois? Ha. Eu nem me lembro do que eu precisava disso.
— 9788 Steve

6

Eu tentei as rotinas Javascript em phpjs.org e elas funcionaram bem.

Tentei pela primeira vez as rotinas sugeridas na resposta escolhida por Ranhiru Cooray - http://ntt.cc/2008/01/19/base64-encoder-decoder-with-javascript.html

Eu descobri que eles não funcionavam em todas as circunstâncias. Eu escrevi um caso de teste em que essas rotinas falham e as postei no GitHub em:

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

Também publiquei um comentário no blog no ntt.cc para alertar o autor (aguardando moderação - o artigo é antigo, portanto não tenho certeza se o comentário será publicado).


1

Prefiro usar os métodos de codificação / decodificação bas64 do CryptoJS , a biblioteca mais popular para algoritmos criptográficos padrão e seguros implementados em JavaScript usando as melhores práticas e padrões.


1

No Node.js, podemos fazê-lo de maneira simples

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

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

0

Para estruturas JavaScripts em que não há atobmétodo e, caso você não queira importar bibliotecas externas, esta é uma função curta.

Ele obteria uma string que contém o valor codificado em Base64 e retornará uma matriz decodificada de bytes (onde a matriz de bytes é representada como matriz de números em que cada número é um número inteiro entre 0 e 255, inclusive).

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

Recursos utilizados: RFC-4648 Seção 4

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.