Pengkodean dan penguraian base64 dalam Javascript sisi klien

Jawaban:

214

Beberapa browser seperti Firefox, Chrome, Safari, Opera dan IE10 + dapat menangani Base64 secara asli. Lihatlah pertanyaan Stackoverflow ini . Ini menggunakan btoa()dan atob()fungsinya .

Untuk JavaScript sisi server (Node), Anda dapat menggunakan Buffers untuk mendekode.

Jika Anda mencari solusi lintas-peramban, ada pustaka yang ada seperti CryptoJS atau kode seperti:

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

Dengan yang terakhir, Anda perlu menguji fungsi secara menyeluruh untuk kompatibilitas lintas browser. Dan kesalahan sudah dilaporkan .

Ranhiru Jude Cooray
sumber
1
Saya menggunakan metode ini untuk menyandikan SVG di base64 dengan skema Tanggal URI. Kejutan: fungsi ini urlencodes setiap karakter, jadi saya mendapatkan XML yang salah format ini pada target:% 3C% 3Fxml% 20versi% 3D% 271.0% 27% 20% 3F% 3E% 3Csvg% 20xmlns% 3D% 27http% ...
Dereckson
21
Node.js dapat melakukan Base64 secara native: new Buffer('Hello, world!').toString('base64'); new Buffer('SGVsbG8sIHdvcmxkIQ==', 'base64').toString('ascii'); (sumber)
nyuszika7h
Dan jika saya ingin melakukannya URL-safe?
anddero
1
di simpul 5+, gunakan Buffer.from, seperti yang new Buffer(string)sudah usang. Buffer.from(jwt.split('.')[1], 'base64').toString()
Ray Foss
63

Di browser berbasis Gecko / WebKit (Firefox, Chrome dan Safari) dan Opera, Anda dapat menggunakan btoa () dan atob () .

Jawaban asli: Bagaimana Anda bisa menyandikan string ke Base64 di JavaScript?

nyuszika7h
sumber
Ini adalah penyelamat. Saya menggunakan beberapa implementasi yang berbeda untuk men-decode string encoding base64 yang sangat besar dan hasilnya selalu salah. atob () berfungsi dengan baik!
b2238488
15
Nitpick kecil: Opera tidak didasarkan pada Gecko atau Webkit, ia menggunakan mesin rendering sendiri yang disebut Presto.
Peter Olson
Wow, terima kasih untuk ini. Tidak tahu ada encoder base64 asli di browser ini!
Rob Porter
5
@PeterOlson Tidak lagi :)
Mustafa
1
Saya menyadari ini adalah posting lama, tetapi tentang kekhawatiran @ b2238488, Anda dapat membagi string base64 sehingga masing-masing panjang token adalah kelipatan dari 4, dan mendekode secara terpisah. Hasilnya akan sama dengan mendekode seluruh string sekaligus.
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!"

Lintas browser

Ditulis ulang dan dimodulasi UTF-8 dan Base64 Javascript Encoding dan Decoding Libraries / Modul untuk AMD, CommonJS, Nodejs dan Browser. Kompatibel lintas browser.


dengan Node.js

Inilah cara Anda menyandikan teks normal ke base64 di 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');

Dan di sini adalah bagaimana Anda mendekodekan string yang disandikan base64:

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

dengan Dojo.js

Untuk menyandikan larik byte menggunakan dojox.encoding.base64:

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

Untuk memecahkan kode string yang disandikan base64:

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

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

Tapi bagaimana caranya?

Jika Anda ingin mempelajari lebih lanjut tentang bagaimana base64 dikodekan secara umum, dan dalam JavaScript khususnya, saya akan merekomendasikan artikel ini: Ilmu komputer dalam JavaScript: pengkodean Base64

davidcondrey
sumber
1
FYI: Versi lintas-browser memiliki beberapa kebocoran jahat dengan c2dan kemungkinan c1dan c3sehingga tidak akan bekerja dengan "use strict"seperti dijelaskan di atas.
Campbeln
41

Ini adalah versi posting Sniper yang diperketat. Ini menganggap string base64 terbentuk dengan baik tanpa carriage return. Versi ini menghilangkan beberapa loop, menambahkan &0xffperbaikan dari Yaroslav, menghilangkan tertinggal nol, ditambah sedikit kode 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;
};
broc.seib
sumber
5
Bahkan lebih sedikit 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
Ya tetapi hanya bekerja dengan ASCII. Karakter Cyr menjadi hancur misalnya.
Martin Kovachev
@ MartinKovachev dapatkah Anda memposting komentar baru dengan teks contoh dengan karakter Cyr dan pengkodean base64 terkait? Mungkin kita dapat memperbaiki kode untuk mengakomodasi.
broc.seib
Di sini: sesuatu seperti itu: тестова фраза
Martin Kovachev
2
@OliverSalzburg Bahkan lebih sedikit menghasilkan tabel kode :):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

Fungsi Dekode JavaScript Base64 pendek dan cepat tanpa 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;
}
Penembak jitu
sumber
6
Opera 11.62 tampaknya memiliki masalah dengan bagian '% 256'. Menggantinya dengan '& 0xff' membuatnya berfungsi.
Yaroslav Stavnichiy
Kode javascript endpoint virtual Tyk tampaknya bermasalah dengan bagian '\ x00'. Menggantinya dengan r = r.replace (/ \ x00 / g, '') membuatnya berfungsi
Panupong Kongarn
11

Proyek php.js memiliki implementasi JavaScript dari banyak fungsi PHP. base64_encodedan base64_decodesudah termasuk.

ceejayoz
sumber
php.js adalah inkarnasi dari semua kejahatan dan milik lapisannya sendiri di neraka. Hindari ini layaknya wabah. (Info lebih lanjut: softwareengineering.stackexchange.com/questions/126671/... )
Coreus
Saya tidak melihat banyak yang mendukung pernyataan selimut di tautan itu, @Coreus. Digunakan dengan bijak, atau sebagai titik awal, ini adalah cara yang bisa diterima untuk mengetahui logika setara di JS untuk sesuatu yang mungkin sudah Anda ketahui bagaimana melakukannya di PHP.
ceejayoz
9

Apakah ada yang mengatakan kode golf? =)

Berikut ini adalah upaya saya untuk meningkatkan cacat saya sambil mengejar ketinggalan zaman. Disediakan untuk kenyamanan Anda.

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

Apa yang sebenarnya saya kejar adalah implementasi asinkron dan yang mengejutkan saya ternyata forEachbertentangan dengan $([]).eachimplementasi metode JQuery yang sangat sinkron.

Jika Anda juga memiliki gagasan gila dalam pikiran penundaan 0 window.setTimeoutakan menjalankan decode base64 asynchronous dan menjalankan fungsi callback dengan hasil ketika selesai.

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

@Toothbrush menyarankan "indeks string seperti array", dan singkirkan split. Rutin ini tampaknya sangat aneh dan tidak yakin seberapa kompatibel itu, tapi itu mengenai birdie lain jadi mari kita memilikinya.

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

Ketika mencoba untuk menemukan informasi lebih lanjut tentang string JavaScript sebagai array saya menemukan tip pro ini menggunakan /./gregex untuk melangkah melalui string. Ini mengurangi ukuran kode bahkan lebih dengan mengganti string di tempat dan menghilangkan kebutuhan menjaga variabel kembali.

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

Namun jika Anda mencari sesuatu yang sedikit lebih tradisional mungkin yang berikut ini lebih sesuai dengan selera Anda.

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

Saya tidak memiliki masalah nol tertinggal sehingga ini dihapus untuk tetap di bawah standar tetapi harus dengan mudah diselesaikan dengan a trim()atau atrimRight() jika Anda mau, jika ini menimbulkan masalah bagi Anda.

yaitu.

return r.trimRight();

catatan:

Hasilnya adalah string byte ascii, jika Anda memerlukan unicode, yang paling mudah adalah escapestring byte yang kemudian dapat didekodekan dengan decodeURIComponentuntuk menghasilkan string unicode.

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

Karena escapesudah tidak digunakan lagi, kita dapat mengubah fungsi kita untuk mendukung unicode secara langsung tanpa perlu escapeatau String.fromCharCodekita dapat menghasilkan %string yang lolos yang siap untuk decoding 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!

nickl-
sumber
3
Anda tidak perlu splitmenggunakan string, karena Anda dapat mengindeks string JavaScript seperti array. s.split('').forEach(function ...dapat digantikan oleh [].forEach.call(s, function .... Seharusnya lebih cepat, karena tidak harus membelah string.
Sikat gigi
Yang "lebih tradisional" benar-benar rusak untuk saya - menghasilkan kekacauan kacau dengan jejak teks asli yang ditaburkan di seluruh. Di Chrome.
Steve Bennett
@Steve Bennett Saya menguji semua varian di chrome ... itu berhasil. Bisakah Anda memberikan contoh string base64 yang gagal?
nickl-
Tiga tahun kemudian? Ha. Aku bahkan tidak ingat untuk apa aku membutuhkan ini.
Steve Bennett
6

Saya telah mencoba rutinitas Javascript di phpjs.org dan mereka telah bekerja dengan baik.

Saya pertama kali mencoba rutinitas yang disarankan dalam jawaban yang dipilih oleh Ranhiru Cooray - http://ntt.cc/2008/01/19/base64-encoder-decoder-with-javascript.html

Saya menemukan bahwa mereka tidak bekerja dalam semua keadaan. Saya menulis uji kasus di mana rutinitas ini gagal dan mempostingnya ke GitHub di:

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

Saya juga memposting komentar ke posting blog di ntt.cc untuk mengingatkan penulis (menunggu moderasi - artikel sudah tua jadi tidak yakin apakah komentar akan diposting).

Scott Carter
sumber
1

Saya lebih suka menggunakan metode encode / decode bas64 dari CryptoJS , perpustakaan paling populer untuk algoritma kriptografi standar dan aman yang diterapkan dalam JavaScript menggunakan praktik dan pola terbaik.

Dan Dascalescu
sumber
1

Di Node.js kita bisa melakukannya dengan cara sederhana

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

console.log(base64_decode); // "Hello World"
KARTHIKEYAN.A
sumber
0

Untuk kerangka kerja JavaScripts di mana tidak ada atobmetode dan jika Anda tidak ingin mengimpor perpustakaan eksternal, ini adalah fungsi pendek yang melakukannya.

Ini akan mendapatkan string yang berisi nilai yang disandikan Base64 dan akan mengembalikan array byte yang didekodekan (di mana array byte diwakili sebagai array angka di mana setiap angka adalah bilangan bulat antara 0 dan 255 inklusif).

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

Sumber yang digunakan: RFC-4648 Bagian 4

Yordan Nedelchev
sumber