Ошибка декодирования Base64 в JavaScript [дубликат]

Js - однопоточная.

Браузер можно разделить на три части:

1) Event Loop

2 ) Web API

3) Очередь событий

Событие Loop запускается вечно, т. Е. Тип бесконечного цикла. Очередь ожидания - это то, где вся ваша функция нажимается на какое-либо событие (пример: нажмите) this один за другим выполняется в очереди и помещается в цикл «Событие», который выполняет эту функцию и подготавливает ее для следующего после первого запуска. Это означает, что выполнение одной функции не начинается до тех пор, пока функция, перед которой она в очереди не будет выполнена цикл событий.

Теперь давайте подумаем, что мы поставили две функции в очереди, чтобы получить данные с сервера, а другой использует эти данные. Мы сначала нажали функцию serverRequest () в очереди, а затем применили функцию Data () , Функция serverRequest переходит в цикл событий и делает вызов на сервер, так как мы никогда не знаем, сколько времени потребуется для получения данных с сервера, поэтому ожидается, что этот процесс займет много времени, и поэтому мы заняли наш цикл событий, тем самым повесив нашу страницу, вот где Web API входит в эту роль, он принимает эту функцию из цикла событий и обращается к серверу, создающему цикл событий, так что мы можем выполнить следующую функцию из очереди. Следующая функция в очереди - useData (), которая идет в цикле, но из-за отсутствия данных отходы и выполнение следующей функции продолжаются до конца очереди (это называется Async-вызовом, то есть мы можем сделать что-то еще, пока не получим данные)

Предположим, что наша функция serverRequest () имела оператор возврата в код, когда мы возвращаем данные с сервера Web API, будет выталкивать его в очередь в конце очереди. По мере того, как он заканчивается в очереди, мы не можем использовать его данные, поскольку в нашей очереди нет функции, чтобы использовать эти данные. Таким образом, невозможно вернуть что-то из Async Call.

Таким образом, решение этой проблемы callback или обещают .

A Изображение из одного из ответов здесь, правильно объясняет использование обратного вызова ... Мы (функция, использующая данные, возвращаемые с сервера), чтобы вызвать вызывающий сервер.

 function doAjax(callbackFunc, method, url) {
  var xmlHttpReq = new XMLHttpRequest();
  xmlHttpReq.open(method, url);
  xmlHttpReq.onreadystatechange = function() {

      if (xmlHttpReq.readyState == 4 && xmlHttpReq.status == 200) {
        callbackFunc(xmlHttpReq.responseText);
      }


  }
  xmlHttpReq.send(null);

}

В моем коде он называется

function loadMyJson(categoryValue){
  if(categoryValue==="veg")
  doAjax(print,"GET","http://localhost:3004/vegetables");
  else if(categoryValue==="fruits")
  doAjax(print,"GET","http://localhost:3004/fruits");
  else 
  console.log("Data not found");
}

Прочитайте здесь новые методы в ECMA (2016/17) для создания асинхронного вызова (@Felix Kling Answer сверху) https://stackoverflow.com/a/14220323/7579856

47
задан brandonscript 7 May 2015 в 16:18
поделиться

6 ответов

В Mozilla MDN есть замечательная статья , которая описывает именно эту проблему:

«Проблема Unicode» Поскольку DOMStrings - это строки с 16-битным кодированием, в большинстве браузеры, вызывающие window.btoa в строке Unicode, вызывают исключение Character Out Of Range, если символ превышает диапазон 8-разрядного символа в кодировке ASCII. Существует два возможных способа решения этой проблемы:

  • первым из них является выход из всей строки, а затем ее кодирование,
  • , второй - преобразование UTF- 16 DOMString в массив символов UTF-8 и затем кодировать его.

Примечание к исходному ответу: ранее в статье MDN было предложено использовать unescape и escape для решения проблемы исключения Character Out Of Range, но с тех пор они устарели. Некоторые другие ответы здесь предложили обойти это с помощью decodeURIComponent и encodeURIComponent, это оказалось ненадежным и непредсказуемым.

В конце концов, вы определенно могли бы сэкономить некоторое горе с помощью библиотеки:

Вот текущая рекомендация, прямо из MDN, с некоторой дополнительной совместимостью TypeScript через @ MA-Maddin:

Кодирование UTF8 ⇢ base64

Реализовать регулярное выражение вместо устаревшей функции unescape

function b64EncodeUnicode(str) {
    return btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, function(match, p1) {
        return String.fromCharCode(parseInt(p1, 16))
    }))
}

b64EncodeUnicode('✓ à la mode') // "4pyTIMOgIGxhIG1vZGU="
b64EncodeUnicode('\n') // "Cg=="

Декодирование base64 ⇢ UTF8

В статье MDN изначально не был пример для декодирования, но теперь добавлено

function b64DecodeUnicode(str) {
    return decodeURIComponent(Array.prototype.map.call(atob(str), function(c) {
        return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2)
    }).join(''))
}

b64DecodeUnicode('4pyTIMOgIGxhIG1vZGU=') // "✓ à la mode"
b64DecodeUnicode('Cg==') // "\n"

Исходное решение (устарело)

Это использовало escape и unescape (которые теперь устарели, хотя это все еще работает во всех современных браузерах):

function utf8_to_b64( str ) {
    return window.btoa(unescape(encodeURIComponent( str )));
}

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

// Usage:
utf8_to_b64('✓ à la mode'); // "4pyTIMOgIGxhIG1vZGU="
b64_to_utf8('4pyTIMOgIGxhIG1vZGU='); // "✓ à la mode"

И последнее: впервые я столкнулся с этой проблемой при вызове API GitHub. Чтобы заставить это работать на (Mobile) Safari должным образом, я фактически должен был удалить все пустое пространство от источника base64 до , я мог бы даже декодировать источник. Является ли это еще актуальным в 2017 году, я не знаю:

function b64_to_utf8( str ) {
    str = str.replace(/\s/g, '');    
    return decodeURIComponent(escape(window.atob( str )));
}
125
ответ дан brandonscript 25 August 2018 в 23:51
поделиться

Вот некоторые будущие коды для браузеров, которые могут отсутствовать escape/unescape(). Обратите внимание, что IE 9 и старше не поддерживают atob/btoa(), поэтому вам нужно будет использовать для них пользовательские функции base64.

// Polyfill for escape/unescape
if( !window.unescape ){
    window.unescape = function( s ){
        return s.replace( /%([0-9A-F]{2})/g, function( m, p ) {
            return String.fromCharCode( '0x' + p );
        } );
    };
}
if( !window.escape ){
    window.escape = function( s ){
        var chr, hex, i = 0, l = s.length, out = '';
        for( ; i < l; i ++ ){
            chr = s.charAt( i );
            if( chr.search( /[A-Za-z0-9\@\*\_\+\-\.\/]/ ) > -1 ){
                out += chr; continue; }
            hex = s.charCodeAt( i ).toString( 16 );
            out += '%' + ( hex.length % 2 != 0 ? '0' : '' ) + hex;
        }
        return out;
    };
}

// Base64 encoding of UTF-8 strings
var utf8ToB64 = function( s ){
    return btoa( unescape( encodeURIComponent( s ) ) );
};
var b64ToUtf8 = function( s ){
    return decodeURIComponent( escape( atob( s ) ) );
};

Более полным примером кодировки и декодирования UTF-8 может быть найдено здесь: http://jsfiddle.net/47zwb41o/

1
ответ дан Beejor 25 August 2018 в 23:51
поделиться

Малая коррекция, unescape и escape устарели, поэтому:

function utf8_to_b64( str ) {
    return window.btoa(decodeURIComponent(encodeURIComponent(str)));
}

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


function b64_to_utf8( str ) {
    str = str.replace(/\s/g, '');    
    return decodeURIComponent(encodeURIComponent(window.atob(str)));
}
1
ответ дан Darkves 25 August 2018 в 23:51
поделиться

, включая вышеописанное решение, если все еще сталкиваются с проблемой, попробуйте, как показано ниже, рассмотрите случай, когда escape не поддерживается для TS.

blob = new Blob(["\ufeff", csv_content]); // this will make symbols to appears in excel 

для csv_content вы можете попробовать, как показано ниже.

function b64DecodeUnicode(str: any) {        
        return decodeURIComponent(atob(str).split('').map((c: any) => {
            return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
        }).join(''));
    }
0
ответ дан Diwakar 25 August 2018 в 23:51
поделиться

Если обрабатывать строки как байты - это больше, вы можете использовать следующие функции

function u_atob(ascii) {
    return Uint8Array.from(atob(ascii), c => c.charCodeAt(0));
}

function u_btoa(buffer) {
    var binary = [];
    var bytes = new Uint8Array(buffer);
    for (var i = 0, il = bytes.byteLength; i < il; i++) {
        binary.push(String.fromCharCode(bytes[i]));
    }
    return btoa(binary.join(''));
}


// example, it works also with astral plane characters such as '                  
4
ответ дан Riccardo Galli 25 August 2018 в 23:51
поделиться

Вещи меняются. Методы escape / unescape устарели.

Вы можете кодировать строку URI перед кодировкой Base64. Обратите внимание, что это не кодирует кодировку UTF8 с кодировкой Base64, а скорее кодирует кодированные в кодировке Base64 данные. Обе стороны должны согласовать одну и ту же кодировку.

См. Рабочий пример здесь: http://codepen.io/anon/pen/PZgbPW

// encode string
var base64 = window.btoa(encodeURIComponent('€ 你好 æøåÆØÅ'));
// decode string
var str = decodeURIComponent(window.atob(tmp));
// str is now === '€ 你好 æøåÆØÅ'

Для проблемы с ОП должна решаться проблема сторонняя библиотека, такая как js-base64 .

11
ответ дан Tedd Hansen 25 August 2018 в 23:51
поделиться
Другие вопросы по тегам:

Похожие вопросы: