Codifica e decodifica Base64 in Javascript lato client


Risposte:


214

Alcuni browser come Firefox, Chrome, Safari, Opera e IE10 + possono gestire Base64 in modo nativo. Dai un'occhiata a questa domanda StackOverflow . Sta usando btoa()e atob()funzioni .

Per JavaScript lato server (nodo), è possibile utilizzare Buffers per decodificare.

Se stai cercando una soluzione cross-browser, ci sono librerie esistenti come CryptoJS o codice come:

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

Con quest'ultimo, è necessario testare accuratamente la funzione per la compatibilità tra browser. E l'errore è già stato segnalato .


1
Ho usato questo metodo per codificare un file SVG in base64 con lo schema URI data. Sorpresa: questa funzione codifica tutti i caratteri, quindi ottengo questo XML non valido sull'obiettivo:% 3C% 3Fxml% 20version% 3D% 271.0% 27% 20% 3F% 3E% 3Csvg% 20xmlns% 3D% 27http% ...
Dereckson

21
Node.js può eseguire Base64 in modo nativo: new Buffer('Hello, world!').toString('base64'); new Buffer('SGVsbG8sIHdvcmxkIQ==', 'base64').toString('ascii'); (fonte)
nyuszika7h

E se volessi farlo senza URL?
anddero,

1
nel nodo 5+, utilizzare Buffer.from, poiché new Buffer(string)è obsoleto. Buffer.from(jwt.split('.')[1], 'base64').toString()
Ray Foss,

63

Nei browser basati su Gecko / WebKit (Firefox, Chrome e Safari) e Opera, puoi utilizzare btoa () e atob () .

Risposta originale: come si può codificare una stringa in Base64 in JavaScript?


Questo è un salvavita. Ho usato alcune implementazioni diverse per decodificare stringhe con codifica Base64 molto grandi e il risultato è stato sempre sbagliato. atob () funziona alla grande!
b2238488

15
Piccolo nitpick: Opera non è basato su Gecko o Webkit, utilizza un proprio motore di rendering chiamato Presto.
Peter Olson,

Wow, grazie per questo. Non sapevo che esistesse un codificatore Base64 nativo in questi browser!
Rob Porter,

5
@PeterOlson Non più :)
Mustafa,

1
Mi rendo conto che questo è un vecchio post, ma riguardo alla preoccupazione di @ b2238488, puoi dividere la stringa base64 in modo che la lunghezza di ogni token sia un multiplo di 4 e decodificarli separatamente. Il risultato sarà lo stesso della decodifica dell'intera stringa in una sola volta.
nyuszika7h

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

Cross-Browser

Librerie / moduli di codifica e decodifica Javascript UTF-8 e Base64 riscritti e modularizzati per AMD, CommonJS, Nodejs e Browser. Compatibile con più browser.


con Node.js

Ecco come codificare il testo normale in base64 in 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');

Ed ecco come decodificare le stringhe codificate in base64:

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

con Dojo.js

Per codificare una matrice di byte utilizzando dojox.encoding.base64:

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

Per decodificare una stringa codificata in 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=');
}]);

Ma come?

Se vuoi saperne di più su come codifica base64 in generale e in JavaScript in particolare, consiglierei questo articolo: Informatica in JavaScript: codifica Base64


1
Cordiali saluti: La versione cross-browser ha alcune cattive perdite con c2e probabilmente c1e c3quindi non funzionerà "use strict"come definito sopra.
Campbeln,

41

Ecco una versione rafforzata del post di Sniper. Presume una stringa base64 ben formata senza ritorni a capo. Questa versione elimina un paio di loop, aggiunge la &0xffcorrezione da Yaroslav, elimina i null finali, oltre a un po 'di codice 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;
};

5
Ancora meno byte; 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,

Sì, ma funziona solo con ASCII. I personaggi di Cyr vengono mutilati per esempio.
Martin Kovachev,

@MartinKovachev puoi pubblicare un nuovo commento con testo di esempio con i caratteri Cyr e la corrispondente codifica base64? Forse possiamo sistemare il codice per adattarlo.
broc.seib,

Qui: qualcosa del genere: тестова фраза
Martin Kovachev,

2
@OliverSalzburg Ancora meno genera tabella codici :):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

Funzione di decodifica JavaScript Base64 breve e veloce senza fail-safe:

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 sembra avere problemi con la parte '% 256'. Sostituendolo con '& 0xff' lo fa funzionare.
Yaroslav Stavnichiy,

Il codice javascript dell'endpoint virtuale Tyk sembra avere problemi con la parte '\ x00'. Sostituendolo con r = r.replace (/ \ x00 / g, '') farlo funzionare
Panupong Kongarn


11

Il progetto php.js ha implementazioni JavaScript di molte delle funzioni di PHP. base64_encodee base64_decodesono inclusi.


php.js è l'incarnazione di tutto il male e appartiene al suo stesso livello all'inferno. Evitalo come la peste. (Ulteriori informazioni: softwareengineering.stackexchange.com/questions/126671/… )
Coreus

Non vedo molto a sostegno di quella affermazione generale in quel link, @Coreus. Usato con giudizio o come punto di partenza, è un modo perfettamente accettabile per capire la logica equivalente in JS per qualcosa che potresti già sapere come fare in PHP.
Ceejayoz,

9

Qualcuno ha detto il codice golf? =)

Quello che segue è il mio tentativo di migliorare il mio handicap, al passo con i tempi. Fornito per la vostra convenienza.

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

Quello che stavo cercando in realtà era un'implementazione asincrona e con mia sorpresa si scopre forEachche l' $([]).eachimplementazione del metodo di JQuery è molto sincrona.

Se anche tu avevi in ​​mente idee così folli, un ritardo 0 window.setTimeouteseguirà la decodifica base64 in modo asincrono ed eseguirà la funzione di richiamata con il risultato al termine.

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

@Toothbrush ha suggerito "indicizza una stringa come un array", e sbarazzati di split. Questa routine sembra davvero strana e non è sicura di quanto sia compatibile, ma colpisce un altro uccellino quindi lasciamolo.

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

Durante il tentativo di trovare ulteriori informazioni su stringa JavaScript come serie mi sono imbattuto in questa pro punta utilizzando /./gun'espressione regolare per passo attraverso una stringa. Ciò riduce ulteriormente le dimensioni del codice sostituendo la stringa in posizione ed eliminando la necessità di mantenere una variabile di ritorno.

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 invece stavi cercando qualcosa di un po 'più tradizionale, forse quanto segue è più di tuo gusto.

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

Non ho avuto il problema nullo finale quindi questo è stato rimosso per rimanere alla pari, ma dovrebbe essere facilmente risolto con un trim()o un trimRight()se preferisci, se questo ti crea un problema.

vale a dire.

return r.trimRight();

Nota:

Il risultato è una stringa di byte ASCII, se è necessario unicode il più semplice è escapela stringa di byte che può quindi essere decodificata decodeURIComponentper produrre la stringa di Unicode.

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

Poiché escapeè deprecato, potremmo modificare la nostra funzione per supportare direttamente Unicode senza la necessità escapeo String.fromCharCodepossiamo produrre una %stringa con escape pronta per la decodifica 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
Non è necessario per splitla stringa, poiché è possibile indicizzare una stringa JavaScript come un array. s.split('').forEach(function ...può essere sostituito da [].forEach.call(s, function .... Dovrebbe essere molto più veloce, a causa del fatto che non è necessario dividere la stringa.
Spazzolino da denti,

Quello "più tradizionale" è stato completamente rotto per me - ha prodotto un pasticcio confuso con tracce di testo originale sparse ovunque. Su Chrome.
Steve Bennett,

@Steve Bennett Ho testato tutte le varianti in cromo ... funziona. Potete fornire una stringa di esempio base64 che non riesce?
nichel-

Tre anni dopo? Ha. Non ricordo nemmeno per cosa mi serviva.
Steve Bennett,

6

Ho provato le routine Javascript su phpjs.org e hanno funzionato bene.

Ho provato per la prima volta le routine suggerite nella risposta scelta da Ranhiru Cooray - http://ntt.cc/2008/01/19/base64-encoder-decoder-with-javascript.html

Ho scoperto che non funzionavano in tutte le circostanze. Ho scritto un caso di prova in cui queste routine falliscono e le ho pubblicate su GitHub su:

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

Ho anche pubblicato un commento sul post del blog su ntt.cc per avvisare l'autore (in attesa di moderazione: l'articolo è vecchio, quindi non sono sicuro se il commento verrà pubblicato).


1

Preferirei usare i metodi di codifica / decodifica bas64 di CryptoJS , la libreria più popolare per algoritmi crittografici standard e sicuri implementati in JavaScript usando le migliori pratiche e schemi.


1

In Node.js possiamo farlo in modo semplice

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

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

0

Per i framework JavaScripts in cui non esiste un atobmetodo e nel caso in cui non si desideri importare librerie esterne, questa è una funzione breve che lo fa.

Otterrebbe una stringa che contiene un valore codificato Base64 e restituirà una matrice decodificata di byte (in cui la matrice di byte è rappresentata come matrice di numeri in cui ogni numero è un numero intero compreso tra 0 e 255 inclusi).

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

Risorse utilizzate: RFC-4648 Sezione 4

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.