การเข้ารหัสและถอดรหัส Base64 ใน Javascript ฝั่งไคลเอ็นต์


270

มีวิธีการใดใน JavaScript ที่สามารถใช้ในการเข้ารหัสและถอดรหัสสตริงโดยใช้การเข้ารหัส base64 ได้หรือไม่?


7
มีความเป็นไปได้ที่ซ้ำกันของวิธีที่คุณเข้ารหัสเป็น Base64 โดยใช้ Javascript
Drew Noakes

คำตอบ:


214

เบราว์เซอร์บางตัวเช่น Firefox, Chrome, Safari, Opera และ IE10 + สามารถรองรับ Base64 ได้ ดูคำถาม Stackoverflowนี้ มันใช้btoa()และatob()ฟังก์ชั่นฟังก์ชั่น

สำหรับ JavaScript ฝั่งเซิร์ฟเวอร์ (โหนด) คุณสามารถใช้ Buffer s เพื่อถอดรหัส

หากคุณต้องการโซลูชันข้ามเบราว์เซอร์มีไลบรารีที่มีอยู่เช่นCryptoJSหรือรหัสเช่น:

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

ด้วยสิ่งหลังนี้คุณจะต้องทดสอบฟังก์ชั่นการทำงานร่วมกันของเบราว์เซอร์อย่างละเอียด และความผิดพลาดได้รับรายงานแล้ว


1
ฉันใช้วิธีนี้เพื่อเข้ารหัส SVG ใน base64 ด้วยรูปแบบ Date URI เซอร์ไพร์ส: ฟังก์ชั่นนี้ urlencodes ตัวละครทุกตัวเพื่อให้ฉันได้รับในรูปแบบนี้ 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

และถ้าฉันต้องการที่จะทำ URL- ปลอดภัยหรือไม่
anddero

1
ในโหนด 5+ ให้ใช้ Buffer.from ตามที่new Buffer(string)ถูกคัดค้าน Buffer.from(jwt.split('.')[1], 'base64').toString()
Ray Foss

63

ในตุ๊กแก / เบราว์เซอร์ WebKit-based (Firefox, Chrome และ Safari) และ Opera คุณสามารถใช้btoa ()และatob ()

คำตอบเดิม: คุณสามารถเข้ารหัสสตริงเป็น Base64 ใน JavaScript ได้อย่างไร?


นี่คือการช่วยชีวิต ฉันใช้การใช้งานที่แตกต่างกันสองสามตัวเพื่อถอดรหัสสตริงที่เข้ารหัส base64 ขนาดใหญ่มากและผลลัพธ์นั้นผิดเสมอ atob () ใช้งานได้ดี!
b2238488

15
Nitpick ขนาดเล็ก: Opera ไม่ได้ขึ้นอยู่กับ Gecko หรือ Webkit แต่จะใช้เอ็นจิ้นการเรนเดอร์ของตัวเองชื่อ Presto
Peter Olson

ว้าวขอบคุณมากสำหรับสิ่งนี้ ไม่ทราบว่ามีตัวเข้ารหัสพื้นฐาน 64 ในเบราว์เซอร์เหล่านี้!
Rob Porter

5
@PeterOlson ไม่อีกต่อไป :)
มุสตาฟา

1
ฉันรู้ว่านี่เป็นโพสต์เก่า แต่เกี่ยวกับความกังวลของ @ b2238488 คุณสามารถแยกสตริง base64 เพื่อให้ความยาวของโทเค็นแต่ละอันมีค่าเป็น 4 เท่าและถอดรหัสแยกต่างหาก ผลลัพธ์จะเหมือนกันกับการถอดรหัสสตริงทั้งหมดในครั้งเดียว
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!"

เบราว์เซอร์

เขียนใหม่และทำให้เป็นโมดูลแบบ UTF-8 และ Base64 Javascript Encoding และถอดรหัสไลบรารี่ / โมดูลสำหรับ AMD, CommonJS, Nodejs และเบราว์เซอร์ เข้ากันได้ข้ามเบราว์เซอร์


กับ Node.js

นี่คือวิธีที่คุณเข้ารหัสข้อความปกติเป็น base64 ใน 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');

และนี่คือวิธีที่คุณถอดรหัสสตริงที่เข้ารหัส base64:

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

ด้วย Dojo.js

ในการเข้ารหัสอาร์เรย์ของไบต์โดยใช้ dojox.encoding.base64:

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

ในการถอดรหัสสตริงที่เข้ารหัสแบบ 64:

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

ซุ้มประตูติดตั้งเชิงมุม -64

<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


1
FYI: รุ่นเบราว์เซอร์ที่มีการรั่วไหลที่น่ารังเกียจบางคนที่มีc2และมีแนวโน้มc1และc3ดังนั้นมันจะไม่ทำงานกับ"use strict"ตามที่ระบุไว้ข้างต้น
Campbeln

41

นี่คือโพสต์ Sniper ที่รัดกุมขึ้น มันถือว่าดีสตริง base64 ที่ดีขึ้นโดยไม่มีการรับคืน รุ่นนี้กำจัดลูปสองสามตัวเพิ่มการ&0xffแก้ไขจาก Yaroslav, กำจัด 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

ใช่ แต่ใช้ได้กับ ASCII เท่านั้น อักขระ Cyr รับ mangled เช่น
Martin Kovachev

@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

โค้ดจาวาสคริปต์ปลายทางเสมือน Tyk ดูเหมือนจะมีปัญหากับส่วน '\ x00' แทนที่ด้วย r = r.replace (/ \ x00 / g, '') ทำให้มันทำงาน
Panupong Kongarn


11

php.jsโครงการมีการใช้งานจาวาสคริของหลายฟังก์ชั่นของ PHP base64_encodeและbase64_decodeรวมอยู่ด้วย


php.js เป็นอวตารของความชั่วร้ายทั้งหมดและเป็นของชั้นของตัวเองในนรก หลีกเลี่ยงมันเหมือนกาฬโรค (ข้อมูลเพิ่มเติม: softwareengineering.stackexchange.com/questions/126671/… )
Coreus

ฉันไม่เห็นการสนับสนุนที่ครอบคลุมการยืนยันในลิงค์นั้น @Coreus ใช้อย่างรอบคอบหรือเป็นจุดเริ่มต้นเป็นวิธีที่ยอมรับได้อย่างสมบูรณ์ในการหาตรรกะที่เทียบเท่าใน JS สำหรับสิ่งที่คุณอาจรู้อยู่แล้วว่าต้องทำใน PHP
ceejayoz

9

มีใครพูดว่า 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;
}

สิ่งที่ฉันเป็นจริงหลังจากนั้นก็คือการใช้งานแบบอะซิงโครนัสและสิ่งที่ฉันประหลาดใจก็คือมันforEachตรงกันข้ามกับ$([]).eachการใช้วิธีการของ JQuery ที่ซิงโครนัสมาก

หากคุณมีความคิดบ้าคลั่งเช่นกันความล่าช้า 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 เป็นอาร์เรย์ที่ฉันสะดุดกับเคล็ดลับโปรนี้โดยใช้/./gregex เพื่อก้าวผ่านสตริง สิ่งนี้จะช่วยลดขนาดรหัสได้มากขึ้นโดยการแทนที่สตริงเข้าที่และไม่จำเป็นต้องเก็บตัวแปรส่งคืน

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 ดังนั้นสิ่งนี้จึงถูกลบทิ้งเพื่อให้อยู่ในระดับที่ตราไว้ แต่ควรแก้ไขได้ด้วยtrim()หรือtrimRight()ถ้าคุณต้องการนี่จะเป็นปัญหาสำหรับคุณ

กล่าวคือ

return r.trimRight();

บันทึก:

ผลที่ได้คือสตริง ASCII ไบต์หากคุณต้องการ Unicode ที่ง่ายที่สุดคือescapeสตริงไบต์ซึ่งสามารถถอดรหัสด้วยdecodeURIComponentการผลิตสตริง Unicode

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

เนื่องจากescapeเราเลิกใช้งานเราสามารถเปลี่ยนฟังก์ชั่นของเราเพื่อรองรับยูนิโค้ดโดยตรงโดยไม่จำเป็นต้องใช้escapeหรือString.fromCharCodeเราสามารถสร้าง%สตริงที่ใช้ Escape พร้อมสำหรับการถอดรหัส 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
คุณไม่จำเป็นต้องsplitใช้สตริงเนื่องจากคุณสามารถสร้างดัชนีสตริง JavaScript เช่นเดียวกับอาร์เรย์ จะถูกแทนที่ด้วยs.split('').forEach(function ... [].forEach.call(s, function ...มันควรจะเร็วกว่ามากเพราะมันไม่จำเป็นต้องแยกสตริง
แปรงสีฟัน

หนึ่ง "แบบดั้งเดิมมากขึ้น" ถูกทำลายอย่างสมบูรณ์สำหรับฉัน - ผลิตยุ่งเหยิงสับสนกับร่องรอยของข้อความต้นฉบับโรยตลอด บน Chrome
Steve Bennett

@Steve Bennett ฉันทดสอบตัวแปรทั้งหมดใน chrome ... มันใช้งานได้ คุณสามารถระบุสตริง base64 ตัวอย่างที่ล้มเหลวได้หรือไม่
nickl-

สามปีต่อมา? ฮ้า ฉันจำไม่ได้ว่าฉันต้องการสิ่งนี้เพื่ออะไร
Steve Bennett

6

ฉันได้ลองใช้ Javascript ประจำที่ phpjs.org และทำงานได้ดี

ฉันลองทำตามปกติที่แนะนำในคำตอบที่เลือกโดย 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

สำหรับเฟรมเวิร์ก JavaScript ที่ไม่มีatobเมธอดและในกรณีที่คุณไม่ต้องการอิมพอร์ตไลบรารีภายนอกนี่เป็นฟังก์ชันแบบสั้นที่ทำ

มันจะได้รับสตริงที่มีค่าที่เข้ารหัส 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

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.