Кодирование и декодирование Base64 в клиентском Javascript

Есть ли в JavaScript какие-либо методы, которые можно использовать для кодирования и декодирования строки с использованием кодировки base64?


person Mo.    schedule 12.05.2010    source источник
comment
возможный дубликат Как можно кодировать в Base64 с помощью Javascript?   -  person Drew Noakes    schedule 06.12.2012
comment
Возможный дубликат Как можно кодировать строку в Base64 в JavaScript?   -  person Flimzy    schedule 30.01.2017


Ответы (16)


Некоторые браузеры, такие как Firefox, Chrome, Safari, Opera и IE10 +, могут изначально обрабатывать Base64. Взгляните на этот вопрос о стеке. Он использует функции btoa() и atob().

Для серверного JavaScript (Node) вы можете использовать Buffers для декодирования.

Если вы собираетесь использовать кросс-браузерное решение, существуют существующие библиотеки, такие как CryptoJS или код вроде:

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

В последнем случае вам необходимо тщательно протестировать функцию на кроссбраузерность. И об ошибке уже сообщалось.

person Ranhiru Jude Cooray    schedule 12.05.2010
comment
Я использовал этот метод для кодирования SVG в base64 со схемой Date URI. Сюрприз: эта функция urlencodes каждый символ, поэтому я получаю этот искаженный XML в target:% 3C% 3Fxml% 20version% 3D% 271.0% 27% 20% 3F% 3E% 3Csvg% 20xmlns% 3D% 27http% ... - person Dereckson; 13.02.2013
comment
Node.js изначально поддерживает Base64: new Buffer('Hello, world!').toString('base64'); new Buffer('SGVsbG8sIHdvcmxkIQ==', 'base64').toString('ascii'); (источник) - person nyuszika7h; 09.07.2014
comment
А если бы я хотел сделать это URL-безопасным? - person Snackoverflow; 18.09.2019
comment
в узле 5+ используйте Buffer.from, поскольку new Buffer(string) устарел. Buffer.from(jwt.split('.')[1], 'base64').toString() - person Ray Foss; 09.10.2019

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

Кроссбраузерность

Переписанные и модульные библиотеки / модули кодирования и декодирования JavaScript UTF-8 и Base64 для 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);

Чтобы декодировать строку в кодировке base64:

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

bower установить 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=');
}]);

Но как?

Если вы хотите узнать больше о том, как кодируется base64 в целом и в JavaScript в частности, я бы порекомендовал эту статью: Информатика в JavaScript: кодировка Base64

person davidcondrey    schedule 15.09.2014
comment
К вашему сведению: кроссбраузерная версия имеет некоторые неприятные утечки с c2 и, вероятно, c1 и c3, поэтому она не будет работать с "use strict", как определено выше. - person Campbeln; 07.01.2015
comment
Используя Node js, я сократил до: new Buffer('SmF2YVNjcmlwdA==', 'base64').toString(). Есть ли какая-то конкретная причина не делать этого? - person Lucas Andrade; 24.07.2020

В браузерах на основе Gecko / WebKit (Firefox, Chrome и Safari) и Opera вы можете использовать btoa () и atob ().

Исходный ответ: Как можно закодировать строку в Base64 в JavaScript?

person nyuszika7h    schedule 15.01.2011
comment
Это спасатель жизни. Я использовал несколько разных реализаций для декодирования очень больших строк в кодировке base64, и результат всегда был неправильным. atob () отлично работает! - person b2238488; 02.08.2011
comment
Небольшая придирка: Opera не основана на Gecko или Webkit, она использует собственный движок рендеринга под названием Presto. - person Peter Olson; 07.04.2012
comment
Вау, спасибо за это. Не знал, что в этих браузерах есть собственный кодировщик base64! - person Rob Porter; 11.10.2012
comment
@PeterOlson Больше нет :) - person Mustafa; 19.11.2013
comment
@Mustafa Использует ли Opera сейчас Webkit? - person Peter Olson; 19.11.2013
comment
@PeterOlson да, они используют Blink (форк WebKit) как Google - person Mustafa; 19.11.2013
comment
Я понимаю, что это старый пост, но что касается @ b2238488, вы можете разделить строку base64 так, чтобы длина каждого токена была кратна 4, и декодировать их отдельно. Результат будет таким же, как при расшифровке сразу всей строки. - person nyuszika7h; 09.12.2013
comment
С ноября 2014 года btoa () и atob () теперь поддерживаются во всех современных браузерах, включая IE10 + caniuse.com / # search = btoa - person EricP; 14.11.2014

Вот усиленная версия поста Снайпера. Он предполагает правильно сформированную строку base64 без возврата каретки. Эта версия устраняет пару циклов, добавляет исправление &0xff от Ярослава, устраняет завершающие нули, а также немного кода для гольфа.

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;
};
person broc.seib    schedule 22.02.2013
comment
Еще меньше байтов; D decodeBase64=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}; - person Der Hochstapler; 30.04.2015
comment
Да, но работает только с ASCII. Например, персонажи Cyr будут искажены. - person Martin Kovachev; 17.09.2015
comment
@MartinKovachev, можете ли вы опубликовать новый комментарий с примером текста с символами Cyr и соответствующей кодировкой base64? Может быть, мы сможем исправить код, чтобы приспособиться. - person broc.seib; 17.09.2015
comment
Вот: примерно так: тестова фраза - person Martin Kovachev; 18.09.2015
comment
@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++; - person Mike; 12.01.2016

Короткая и быстрая функция декодирования 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;
}
person Sniper    schedule 17.06.2010
comment
В Opera 11.62 проблема с частью "% 256". Замена его на & 0xff заставляет его работать. - person Yaroslav Stavnichiy; 01.05.2012
comment
Код javascript виртуальной конечной точки Tyk, похоже, имеет проблему с частью '\ x00'. Замена его на r = r.replace (/ \ x00 / g, '') заставит его работать - person Panup Pong; 14.02.2020

function b64_to_utf8( str ) {
  return decodeURIComponent(escape(window.atob( str )));
}

https://developer.mozilla.org/en-US/docs/Web/API/WindowBase64/Base64_encoding_and_decoding#The_.22Unicode_Problem.22

person PPB    schedule 14.04.2015
comment
escape устарел: ecma-international.org/ecma-262/9.0/ - person David Braun; 20.10.2019

В проекте php.js есть реализации JavaScript многих функций PHP. base64_encode и base64_decode включены.

person ceejayoz    schedule 13.05.2010
comment
php.js - это воплощение всего зла и принадлежит его собственному слою в аду. Избегайте этого, как чумы. (Подробнее: softwareengineering.stackexchange.com/questions/126671/) - person Coreus; 03.04.2019
comment
Я не вижу особой поддержки этого общего утверждения в этой ссылке, @Coreus. При разумном использовании или в качестве отправной точки это вполне приемлемый способ выяснить эквивалентную логику в JS для того, что вы, возможно, уже знаете, как делать в PHP. - person ceejayoz; 03.04.2019

Кто-то сказал кодируйте гольф? знак равно

Следующее - моя попытка улучшить свой гандикап, идя в ногу со временем. Поставляется для вашего удобства.

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 как массиве, я наткнулся на этот профессиональный совет с использованием регулярного выражения /./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;
}

У меня не было конечной проблемы с нулевым значением, поэтому она была удалена, чтобы оставаться ниже номинальной, но ее можно легко решить с помощью trim() или trimRight(), если вы предпочитаете, если это создаст для вас проблему.

ie.

return r.trimRight();

Примечание:

Результатом является строка байтов ascii, если вам нужен Unicode, самым простым является escape байтовая строка, которая затем может быть декодирована с помощью decodeURIComponent для создания строки Unicode.

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

Поскольку escape устарел, мы можем изменить нашу функцию для поддержки юникода напрямую без необходимости 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);
  }));
}

nJoy!

person nickl-    schedule 08.02.2014
comment
Вам не нужно split строку, так как вы можете индексировать строку JavaScript как массив. s.split('').forEach(function ... можно заменить на [].forEach.call(s, function .... Это должно быть намного быстрее, так как не нужно разбивать строку. - person Toothbrush; 28.07.2014
comment
Более традиционный для меня полностью сломался - произвел искаженный беспорядок со следами оригинального текста, разбросанными повсюду. В Chrome. - person Steve Bennett; 03.06.2015
comment
@Steve Bennett Я тестировал все варианты в хроме ... работает. Можете ли вы предоставить пример строки base64, которая не работает? - person nickl-; 10.05.2018
comment
Три года спустя? Ха. Я даже не помню, для чего мне это было нужно. - person Steve Bennett; 10.05.2018

Я пробовал подпрограммы Javascript на phpjs.org, и они хорошо зарекомендовали себя.

Сначала я попробовал процедуры, предложенные в выбранном ответе Ранхиру Курей - http://ntt.cc/2008/01/19/base64-encoder-decoder-with-javascript.html

Я обнаружил, что они работают не при всех обстоятельствах. Я написал тестовый пример, в котором эти процедуры не работают, и разместил их на GitHub по адресу:

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

Я также разместил комментарий к сообщению в блоге на ntt.cc, чтобы предупредить автора (ожидает модерации - статья устарела, поэтому не уверен, будет ли опубликован комментарий).

person Scott Carter    schedule 30.01.2013

Как бы то ни было, меня вдохновили другие ответы, и я написал небольшую утилиту, которая вызывает API-интерфейсы конкретной платформы для универсального использования либо из Node.js, либо из браузера:

/**
 * Encode a string of text as base64
 *
 * @param data The string of text.
 * @returns The base64 encoded string.
 */
function encodeBase64(data: string) {
    if (typeof btoa === "function") {
        return btoa(data);
    } else if (typeof Buffer === "function") {
        return Buffer.from(data, "utf-8").toString("base64");
    } else {
        throw new Error("Failed to determine the platform specific encoder");
    }
}

/**
 * Decode a string of base64 as text
 *
 * @param data The string of base64 encoded text
 * @returns The decoded text.
 */
function decodeBase64(data: string) {
    if (typeof atob === "function") {
        return atob(data);
    } else if (typeof Buffer === "function") {
        return Buffer.from(data, "base64").toString("utf-8");
    } else {
        throw new Error("Failed to determine the platform specific decoder");
    }
}

person kraenhansen    schedule 30.06.2020

Современные браузеры имеют встроенные функции javascript для кодирования Base64 btoa () и декодирования atob (). Дополнительная информация о поддержке в более старых версиях браузеров: https://caniuse.com/?search=atob

Однако имейте в виду, что функции atob и btoa работают только для кодировки ASCII. Если вам нужны функции Base64 для кодировки UTF-8, вы можете сделать это с помощью:

function base64_encode(s) {      
    return btoa(unescape(encodeURIComponent(s)));
}
function base64_decode(s) {      
    return decodeURIComponent(escape(atob(s)));
}
person D Cruse    schedule 24.10.2020
comment
Спасибо! Это было очень красиво и просто - person sebasira; 22.06.2021

В Node.js это можно сделать простым способом

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

console.log(base64_decode); // "Hello World"
person KARTHIKEYAN.A    schedule 28.11.2017

Я бы предпочел использовать методы кодирования / декодирования bas64 из CryptoJS, наиболее популярная библиотека для стандартных и безопасных криптографических алгоритмов, реализованных на JavaScript с использованием лучших практик и шаблонов.

person Dan Dascalescu    schedule 17.11.2013

Фронтенд: хорошие решения выше, но быстро для бэкэнда ...

NodeJS - без устаревания

Используйте 1_.

> inBase64 = Buffer.from('plain').toString('base64')
'cGxhaW4='

> // DEPRECATED //
> new Buffer(inBase64, 'base64').toString()
'plain'
> (node:1188987) [DEP0005] DeprecationWarning: Buffer() is deprecated due to security and usability issues. Please use the Buffer.alloc(), Buffer.allocUnsafe(), or Buffer.from() methods instead.
(Use `node --trace-deprecation ...` to show where the warning was created)

// Works //
> Buffer.from(inBase64, 'base64').toString()
'plain'
person ecoologic    schedule 09.07.2021

Для фреймворков JavaScripts, где нет метода 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.

person Yordan Nedelchev    schedule 27.03.2020

Base64 Декодирование Win-1251 для кодировок, кроме acsi или iso-8859-1.

Как оказалось, все скрипты, которые я здесь видел, конвертируют кириллицу Base64 в кодировку iso-8859-1. Странно, что этого никто не заметил.

Таким образом, для восстановления кириллицы достаточно произвести дополнительную перекодировку текста с iso-8859-1 на windows-1251.

Думаю, что и с другими языками будет так же. Просто смени кириллицу windows-1251 на свою.

... и спасибо Der Hochstapler за его код, я взял из его комментария ... излишнего комментария, что несколько необычно.

код для JScript (только для рабочего стола Windows) (ActiveXObject) - кодировка файла 1251

decode_base64=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};
sDOS2Win = function(sText, bInsideOut) {
    var aCharsets = ["iso-8859-1", "windows-1251"];
    sText += "";
    bInsideOut = bInsideOut ? 1 : 0;
    with (new ActiveXObject("ADODB.Stream")) { //http://www.w3schools.com/ado/ado_ref_stream.asp
        type = 2; //Binary 1, Text 2 (default) 
        mode = 3; //Permissions have not been set 0,  Read-only 1,  Write-only 2,  Read-write 3,  
        //Prevent other read 4,  Prevent other write 8,  Prevent other open 12,  Allow others all 16
        charset = aCharsets[bInsideOut]; 
        open();
        writeText(sText);
        position = 0;
        charset = aCharsets[1 - bInsideOut];
        return readText();
    }
}
var base64='0PPx8ero5SDh8+ru4uroIQ=='
text = sDOS2Win(decode_base64(base64), false );
WScript.Echo(text)
var x=WScript.StdIn.ReadLine();
person Garric    schedule 27.04.2021