Node.js löst den Fehler "btoa ist nicht definiert" aus


228

In meiner Anwendung node.js habe ich eine Funktion ausgeführt, npm install btoa-atobdamit ich die Funktionen btoa () und atob () verwenden kann, die in clientseitigem Javascript enthalten sind, aber aus irgendeinem Grund nicht in node enthalten sind. Das neue Verzeichnis wurde in meinem Ordner node_modules angezeigt, der sich neben app.js im Stammverzeichnis befindet. Dann habe ich sichergestellt, dass btoa-atob als Abhängigkeit in meiner Datei package.json im Stammverzeichnis hinzugefügt wird.

Aus irgendeinem Grund wird es jedoch immer noch nicht funktionieren.

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

^ sollte "SGVsbG8gV29ybGQh" an die Konsole ausgeben, aber stattdessen erhalte ich den Fehler "btoa ist nicht definiert".

Habe ich die Installation nicht richtig durchgeführt? Was habe ich übersehen?

Antworten:


536

Das Modul 'btoa-atob' exportiert keine programmatische Schnittstelle, sondern bietet nur Befehlszeilenprogramme.

Wenn Sie auf Base64 konvertieren müssen, können Sie dies mit Buffer tun:

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

Umgekehrt (vorausgesetzt, der Inhalt, den Sie dekodieren, ist eine utf8-Zeichenfolge):

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

Hinweis: Verwenden Sie vor Node v4 new Bufferanstelle von Buffer.from.


56

Die hier veröffentlichten Lösungen funktionieren nicht in Nicht-ASCII-Zeichen (dh wenn Sie planen, base64 zwischen Node.js und einem Browser auszutauschen). Damit es funktioniert, müssen Sie den Eingabetext als 'binär' markieren.

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

Das gibt dir SOlsbPMgd/NybGQhIQ==. Wenn Sie atob('SOlsbPMgd/NybGQhIQ==')in einem Browser machen, wird es auf die richtige Weise dekodiert. Es wird es auch in Node.js richtig machen über:

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

Wenn Sie den "binären Teil" nicht ausführen, werden die Sonderzeichen falsch dekodiert.

Ich habe es von der Implementierung des btoa npm-Pakets erhalten :


1
Danke, ich war verrückt nach veränderten Charakteren.
Matthew James Briggs

1
Danke Ivan, ich hätte Stunden damit verbracht ... deine Antwort sollte die akzeptierte sein!
Pawel

Iván Alegre Verwenden Sie einfach keine 'binäre' Codierung. Wenn Sie dies tun Buffer.from('Hélló wórld!!').toString('base64'), erhalten Sie eine SOlsbPMgd/NybGQhIQ==Datei, die ordnungsgemäß in Nicht-ASCII-Zeichenfolgen konvertiert werden kann.
TotalAMD

1
@TotalAMD es wird nicht funktionieren, base64 von Node.js zu Browser oder umgekehrt auszutauschen
Iván Alegre

3
Sie vergleichen die Codierung in base64 und decodieren sie auf derselben Plattform. Chrome zu Chrome und Node zu Node. Wenn Sie es in Knoten 10 ohne Binärdatei codieren, wird es geben SMOpbGzDsyB3w7NybGQhIQ==. Wenn Sie dies in einem Browser dekodieren, erhalten Sie Hélló wórld!!. Die Binärdatei ist perfekt, um die plattformübergreifende Kompatibilität sicherzustellen.
Iván Alegre

22

Mein Team ist auf dieses Problem gestoßen, als es Node mit React Native und PouchDB verwendet hat. So haben wir es gelöst ...

NPM-Installationspuffer:

$ npm install --save buffer

Stellen Sie sicher Buffer, btoaund atobwerden als Globals geladen:

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
Der Befehl new Buffer () in Ihrem Code gibt in neueren Versionen des Knotens den folgenden Fehler aus: [DEP0005] DeprecationWarning: Buffer () ist aufgrund von Sicherheits- und Usability-Problemen veraltet. Verwenden Sie stattdessen die Methoden Buffer.alloc (), Buffer.allocUnsafe () oder Buffer.from ().
Rodrigo De Almeida Siqueira

8

Ich stellte fest, dass die Shims aus den obigen Antworten zwar funktionierten, jedoch nicht mit dem Verhalten der Implementierungen von btoa()und durch Desktop-Browser übereinstimmten 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])));

Wie sich herausstellt, Bufferrepräsentieren / interpretieren Instanzen Zeichenfolgen, die standardmäßig in UTF-8 codiert sind . Im Gegensatz dazu können Sie in Desktop-Chrome nicht einmal eine Zeichenfolge eingeben, die Zeichen außerhalb des Bereichs latin1 enthält btoa(), da dies eine Ausnahme auslöst :Uncaught DOMException: Failed to execute 'btoa' on 'Window': The string to be encoded contains characters outside of the Latin1 range.

Daher müssen Sie explizit den eingestellten Codierungstyp an latin1, um für Ihre Node.js Shim die Codierung Art von Desktop - Chrome zum Spiel:

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

In Knoten v0.12.2 gibt es keine Buffer.from-Funktion
Zibri

@Zibri Node v0.12.2 ist uralt und hat vor zwei Jahren das Lebensende erreicht . Buffer.from()ist aus Sicherheitsgründen die empfohlene Methode zur Verwendung der Puffer-API (obwohl dieser Link Alternativen zu Buffer.from()den möglicherweise für Node v0.12.2 geltenden Alternativen verdeutlicht).
Jamie Birch

Ich verstehe das, aber auf einem eingebetteten Gerät habe ich diese Version.
Zibri

Ich führe meinen Code in Atom mit dem Skriptpaket github.com/rgbkrk/atom-script aus , das eine alte Implementierung von node ist. Mit anderen Worten, es benötigt auch eine Implementierung für btoa, während es mit Buffer.from () nicht fertig wird.
Shrimpy

4

Ich habe einen Code, der zwischen Server und Client geteilt wird, und ich brauchte eine Implementierung von btoa darin. Ich habe versucht, etwas zu tun wie:

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

aber der Server würde zerquetschen mit:

ReferenceError: btoa ist nicht definiert

while Bufferist auf dem Client nicht definiert.

Ich konnte window.btoa nicht überprüfen (es ist ein gemeinsam genutzter Code, erinnerst du dich?)

Also bin ich zu dieser Implementierung gekommen:

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

1

Ich verstehe, dass dies ein Diskussionspunkt für eine Knotenanwendung ist, aber im Interesse universeller JavaScript-Anwendungen, die auf einem Knotenserver ausgeführt werden. So bin ich zu diesem Beitrag gekommen. Ich habe dies für eine universelle / isomorphe Reaktionsanwendung untersucht, die ich war Gebäude, und das Paket ababfunktionierte für mich. Tatsächlich war es die einzige Lösung, die funktionierte, anstatt die ebenfalls erwähnte Puffermethode zu verwenden (ich hatte Probleme mit dem Typoskript).

(Dieses Paket wird von verwendet jsdom, was wiederum vom windowPaket verwendet wird.)

Zurück zu meinem Punkt; Auf dieser Grundlage könnten Sie das ababPaket möglicherweise installieren und verwenden , anstatt eine eigene Funktion zu schreiben, die möglicherweise vorhanden ist oder nicht , wenn diese Funktionalität bereits als npm-Paket wie das von Ihnen erwähnte geschrieben ist und über einen eigenen Algorithmus verfügt, der auf der W3-Spezifikation basiert genau basierend auf der Codierung.

--- BEARBEITEN ---

Ich hatte heute seltsame Probleme mit der Codierung (nicht sicher, warum es jetzt passiert) mit dem Paket abab. Es scheint die meiste Zeit korrekt zu codieren, aber manchmal codiert es im Frontend falsch. Verbrachte lange Zeit mit dem Debuggen, wechselte aber base-64wie empfohlen zum Paket und es funktionierte sofort. Schien definitiv auf den base64-Algorithmus von zurückzuführen zu sein abab.


1

Das gleiche Problem mit dem 'script'-Plugin im Atom-Editor, einer alten Version des Knotens, der weder btoa () noch atob () enthält, noch den Buffer-Datentyp unterstützt. Der folgende Code macht den Trick:

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=='));


Das funktioniert danke. In meinem Fall verwende ich ChakraEngine, das atob nicht zu unterstützen scheint.
Wasser


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

Hier ist eine übersichtliche universelle Lösung für die Base64-Codierung:

const nodeBtoa = (b) => Buffer.from(b).toString('base64');
export const base64encode = typeof btoa !== 'undefined' ? btoa : nodeBtoa;
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.