Node.js выдает ошибку «что не определено»


231

В моем приложении node.js я сделал npm install btoa-atobтак, чтобы я мог использовать функции btoa () и atob (), которые встроены в клиентский JavaScript, но по какой-то причине не были включены в узел. Новый каталог появился в моей папке node_modules, которая сама находится в корне вместе с app.js. Затем я убедился, что добавил btoa-atob в качестве зависимости в мой файл package.json, который находится в корневом каталоге.

Однако по какой-то причине это все равно не будет работать.

console.log(btoa("Hello World!"));

^ должен вывести «SGVsbG8gV29ybGQh» на консоль, но вместо этого я получаю ошибку «btoa не определен».

Я не сделал установку правильно? Что я упустил?

Ответы:


540

Модуль 'btoa-atob' не экспортирует программный интерфейс, он предоставляет только утилиты командной строки.

Если вам нужно конвертировать в Base64, вы можете сделать это, используя Buffer:

console.log(Buffer.from('Hello World!').toString('base64'));

Обратное (при условии, что содержимое, которое вы декодируете, является строкой utf8):

console.log(Buffer.from(b64Encoded, 'base64').toString());

Примечание: до Node v4 используйте, new Bufferа не Buffer.from.


57

Решения, опубликованные здесь, не работают в не-ascii символах (т.е. если вы планируете обмен base64 между Node.js и браузером). Чтобы заставить его работать, вы должны пометить входной текст как «двоичный».

Buffer.from('Hélló wórld!!', 'binary').toString('base64')

Это дает вам SOlsbPMgd/NybGQhIQ==. Если вы делаете atob('SOlsbPMgd/NybGQhIQ==')в браузере, он будет правильно декодировать. Это будет сделано правильно и в Node.js через:

Buffer.from('SOlsbPMgd/NybGQhIQ==', 'base64').toString('binary')

Если вы не выполняете «двоичную часть», вы будете неправильно декодировать специальные символы.

Я получил это от реализации пакета btoa npm :


1
спасибо, я сходил с ума от изменившихся персонажей.
Мэтью Джеймс Бриггс

1
Спасибо, Иван, я бы потратил на это часы ... ваш ответ должен быть принятым!
Павел

Иван Алегре Только не используйте двоичную кодировку. Если вы это сделаете Buffer.from('Hélló wórld!!').toString('base64')- это даст вам, SOlsbPMgd/NybGQhIQ==что может быть преобразовано в не-ASCII строки обратно должным образом.
TotalAMD

1
@TotalAMD это не сработает при обмене base64 из Node.js в браузер или наоборот
Иван Алегре

3
Вы сравниваете кодировку в base64 и декодируете ее на той же платформе. Хром в Хром и Узел в Узел. Если вы закодируете его в Node 10 без двоичного кода, это даст SMOpbGzDsyB3w7NybGQhIQ==. Если вы расшифруете это в браузере, это даст вам Hélló wórld!!. Двоичный файл идеально подходит для обеспечения кросс-платформенной совместимости.
Иван Алегре

22

Моя команда столкнулась с этой проблемой при использовании Node с React Native и PouchDB. Вот как мы решили это ...

Буфер установки NPM:

$ npm install --save buffer

Убедитесь Buffer, btoaи atobзагружены как глобальные:

global.Buffer = global.Buffer || require('buffer').Buffer;

if (typeof btoa === 'undefined') {
  global.btoa = function (str) {
    return new Buffer(str, 'binary').toString('base64');
  };
}

if (typeof atob === 'undefined') {
  global.atob = function (b64Encoded) {
    return new Buffer(b64Encoded, 'base64').toString('binary');
  };
}

2
Команда new Buffer () в вашем коде выдает следующую ошибку в более новых версиях узла: [DEP0005] DeprecationWarning: Buffer () устарела из-за проблем безопасности и удобства использования. Пожалуйста, используйте взамен методы Buffer.alloc (), Buffer.allocUnsafe () или Buffer.from ().
Родриго де Алмейда Сикейра

8

Я обнаружил, что, хотя шайбы из приведенных выше ответов работали, они не соответствовали поведению реализаций настольных браузеров btoa()и atob():

const btoa = function(str){ return Buffer.from(str).toString('base64'); }
// returns "4pyT", yet in desktop Chrome would throw an error.
btoa('✓');
// returns "fsO1w6bCvA==", yet in desktop Chrome would return "fvXmvA=="
btoa(String.fromCharCode.apply(null, new Uint8Array([0x7e, 0xf5, 0xe6, 0xbc])));

Как оказывается, Buffer экземпляры представляют / интерпретируют строки, закодированные в UTF-8 по умолчанию . Напротив, в настольном Chrome вы даже не можете ввести строку, содержащую символы за пределами диапазона latin1 btoa(), поскольку это вызовет исключение:Uncaught DOMException: Failed to execute 'btoa' on 'Window': The string to be encoded contains characters outside of the Latin1 range.

Следовательно, вам необходимо явно установить тип кодировки, чтобы latin1ваша оболочка Node.js соответствовала типу кодировки Chrome на рабочем столе:

const btoaLatin1 = function(str) { return Buffer.from(str, 'latin1').toString('base64'); }
const atobLatin1 = function(b64Encoded) {return Buffer.from(b64Encoded, 'base64').toString('latin1');}

const btoaUTF8 = function(str) { return Buffer.from(str, 'utf8').toString('base64'); }
const atobUTF8 = function(b64Encoded) {return Buffer.from(b64Encoded, 'base64').toString('utf8');}

btoaLatin1('✓'); // returns "Ew==" (would be preferable for it to throw error because this is undecodable)
atobLatin1(btoa('✓')); // returns "\u0019" (END OF MEDIUM)

btoaUTF8('✓'); // returns "4pyT"
atobUTF8(btoa('✓')); // returns "✓"

// returns "fvXmvA==", just like desktop Chrome
btoaLatin1(String.fromCharCode.apply(null, new Uint8Array([0x7e, 0xf5, 0xe6, 0xbc])));
// returns "fsO1w6bCvA=="
btoaUTF8(String.fromCharCode.apply(null, new Uint8Array([0x7e, 0xf5, 0xe6, 0xbc])));

в узле v0.12.2 нет функции
Buffer.from

@Zibri Node v0.12.2 является древним и закончился два года назад . Buffer.from()это рекомендуемый способ использования API буфера по соображениям безопасности (хотя эта ссылка прояснит альтернативы, Buffer.from()которые могут применяться для Node v0.12.2).
Джейми Берч

Я понимаю это, но на встроенном устройстве у меня есть эта версия.
Зибри

Я выполняю свой код в Atom, используя пакет сценариев github.com/rgbkrk/atom-script, который является старой реализацией узла. Другими словами, ему также нужна реализация для btoa, хотя он не может справиться с Buffer.from ().
Креветки

4

У меня есть общий код между сервером и клиентом, и мне нужна была реализация btoa внутри него. Я пытался сделать что-то вроде:

const btoaImplementation =  btoa || (str => Buffer.from(str).toString('base64'));

но сервер рухнет с:

ReferenceError: btoa не определено

пока Bufferне определено на клиенте.

Я не смог проверить window.btoa (это общий код, помните?)

Итак, я закончил с этой реализацией:

const btoaImplementation = str => {
    try {
        return btoa(str);
    } catch(err) {
        return Buffer.from(str).toString('base64')
    }
};

1

Я понимаю, что это является предметом обсуждения для приложения узла, но в интересах универсальных приложений JavaScript, работающих на сервере узла, и именно так я дошел до этого поста, я исследовал это для приложения универсального / изоморфного реагирования, которым я был здание, и пакет ababработал для меня. Фактически, это было единственное решение, которое я смог найти, и оно работало, вместо того, чтобы использовать метод Buffer, также упомянутый (у меня были проблемы с машинописью).

(Этот пакет используется jsdom, который, в свою очередь, используетсяwindow пакетом.)

Возвращаясь к моей точке зрения; Исходя из этого, возможно, если эта функциональность уже написана в виде пакета npm, подобного тому, который вы упомянули, и имеет собственный алгоритм, основанный на спецификации W3, вы можете установить и использоватьabab пакет, а не писать свою собственную функцию, которая может или не может быть точный на основе кодирования.

--- РЕДАКТИРОВАТЬ ---

Сегодня у меня начались странные проблемы с кодировкой (не знаю, почему это стало происходить сейчас) с пакетом abab. Кажется, что в большинстве случаев он правильно кодируется, но иногда на внешнем интерфейсе кодируется неправильно. Потратил много времени на попытки отладки, но переключился на пакет base-64в соответствии с рекомендациями, и он сразу заработал. Определенно, похоже, что до алгоритма base64 abab.


1

Та же проблема с плагином 'script' в редакторе Atom, который является старой версией узла, не имеет ни btoa (), ни atob (), а также не поддерживает тип данных Buffer. Следующий код делает свое дело:

var Base64 = new function() {
  var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="
  this.encode = function(input) {
    var output = "";
    var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
    var i = 0;
    input = Base64._utf8_encode(input);
    while (i < input.length) {
      chr1 = input.charCodeAt(i++);
      chr2 = input.charCodeAt(i++);
      chr3 = input.charCodeAt(i++);
      enc1 = chr1 >> 2;
      enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
      enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
      enc4 = chr3 & 63;
      if (isNaN(chr2)) {
        enc3 = enc4 = 64;
      } else if (isNaN(chr3)) {
        enc4 = 64;
      }
      output = output + keyStr.charAt(enc1) + keyStr.charAt(enc2) + keyStr.charAt(enc3) + keyStr.charAt(enc4);
    }
    return output;
  }

  this.decode = function(input) {
    var output = "";
    var chr1, chr2, chr3;
    var enc1, enc2, enc3, enc4;
    var i = 0;
    input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
    while (i < input.length) {
      enc1 = keyStr.indexOf(input.charAt(i++));
      enc2 = keyStr.indexOf(input.charAt(i++));
      enc3 = keyStr.indexOf(input.charAt(i++));
      enc4 = keyStr.indexOf(input.charAt(i++));
      chr1 = (enc1 << 2) | (enc2 >> 4);
      chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
      chr3 = ((enc3 & 3) << 6) | enc4;
      output = output + String.fromCharCode(chr1);
      if (enc3 != 64) {
        output = output + String.fromCharCode(chr2);
      }
      if (enc4 != 64) {
        output = output + String.fromCharCode(chr3);
      }
    }
    output = Base64._utf8_decode(output);
    return output;
  }

  this._utf8_encode = function(string) {
    string = string.replace(/\r\n/g, "\n");
    var utftext = "";
    for (var n = 0; n < string.length; n++) {
      var c = string.charCodeAt(n);
      if (c < 128) {
        utftext += String.fromCharCode(c);
      } else if ((c > 127) && (c < 2048)) {
        utftext += String.fromCharCode((c >> 6) | 192);
        utftext += String.fromCharCode((c & 63) | 128);
      } else {
        utftext += String.fromCharCode((c >> 12) | 224);
        utftext += String.fromCharCode(((c >> 6) & 63) | 128);
        utftext += String.fromCharCode((c & 63) | 128);
      }
    }
    return utftext;
  }

  this._utf8_decode = function(utftext) {
    var string = "";
    var i = 0;
    var c = 0,
      c1 = 0,
      c2 = 0,
      c3 = 0;
    while (i < utftext.length) {
      c = utftext.charCodeAt(i);
      if (c < 128) {
        string += String.fromCharCode(c);
        i++;
      } else if ((c > 191) && (c < 224)) {
        c2 = utftext.charCodeAt(i + 1);
        string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
        i += 2;
      } else {
        c2 = utftext.charCodeAt(i + 1);
        c3 = utftext.charCodeAt(i + 2);
        string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
        i += 3;
      }
    }
    return string;
  }
}()

var btoa = Base64.encode;
var atob = Base64.decode;

console.log("btoa('A') = " + btoa('A'));
console.log("btoa('QQ==') = " + atob('QQ=='));
console.log("btoa('B') = " + btoa('B'));
console.log("btoa('Qg==') = " + atob('Qg=='));


Это работает, спасибо. В моем случае я использую ChakraEngine, который не поддерживает atob.
Вода


0
export const universalBtoa = str => {
  try {
    return btoa(str);
  } catch (err) {
    return Buffer.from(str).toString('base64');
  }
};

export const universalAtob = b64Encoded => {
  try {
    return atob(b64Encoded);
  } catch (err) {
    return Buffer.from(b64Encoded, 'base64').toString();
  }
};

0

Вот краткое универсальное решение для кодирования base64:

const nodeBtoa = (b) => Buffer.from(b).toString('base64');
export const base64encode = typeof btoa !== 'undefined' ? btoa : nodeBtoa;
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.