Node.js renvoie l'erreur «btoa n'est pas défini»


231

Dans mon application node.js, j'ai fait un npm install btoa-atobpour pouvoir utiliser les fonctions btoa () et atob () qui sont natives en javascript côté client mais pour une raison quelconque, elles n'étaient pas incluses dans node. Le nouveau répertoire est apparu dans mon dossier node_modules, qui est lui-même en racine à côté de app.js. Ensuite, je me suis assuré d'ajouter btoa-atob comme dépendance dans mon fichier package.json qui est en racine.

Cependant, pour une raison quelconque, cela ne fonctionnera toujours pas.

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

^ devrait afficher "SGVsbG8gV29ybGQh" sur la console, mais à la place, j'obtiens l'erreur "btoa n'est pas défini".

N'ai-je pas fait l'installation correctement? Qu'est-ce que j'ai oublié?

Réponses:


540

Le module 'btoa-atob' n'exporte pas une interface de programmation, il fournit uniquement des utilitaires de ligne de commande.

Si vous devez convertir en Base64, vous pouvez le faire en utilisant Buffer:

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

Inverse (en supposant que le contenu que vous décodez est une chaîne utf8):

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

Remarque: avant Node v4, utilisez new Bufferplutôt que Buffer.from.


57

Les solutions publiées ici ne fonctionnent pas en caractères non ascii (c'est-à-dire si vous prévoyez d'échanger base64 entre Node.js et un navigateur). Pour le faire fonctionner, vous devez marquer le texte saisi comme «binaire».

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

Cela vous donne SOlsbPMgd/NybGQhIQ==. Si vous faites atob('SOlsbPMgd/NybGQhIQ==')dans un navigateur, il le décodera de la bonne manière. Il le fera également dans Node.js via:

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

Si vous ne faites pas la "partie binaire", vous décoderez à tort les caractères spéciaux.

Je l'ai obtenu de l'implémentation du package btoa npm :


1
merci, je devenais fou avec des personnages changés.
— Matthew James Briggs

1
Merci Ivan, j'aurais passé des heures là-dedans ... ta réponse devrait être celle acceptée!
— Pawel

Iván Alegre N'utilisez simplement pas l'encodage «binaire». Si vous le faites Buffer.from('Hélló wórld!!').toString('base64')- cela vous donnera ce SOlsbPMgd/NybGQhIQ==qui peut être converti en chaîne non ascii correctement.
— TotalAMD

1
@TotalAMD cela ne fonctionnera pas en échangeant base64 de Node.js vers un navigateur ou vice
— Iván Alegre

3
Vous comparez l'encodage en base64 et le décodage sur la même plate-forme. Chrome à Chrome et Node à Node. Si vous l'encodez dans le Node 10 sans binaire, cela donnera SMOpbGzDsyB3w7NybGQhIQ==. Si vous décodez cela dans un navigateur, cela vous donnera Hélló wórld!!. Le binaire est parfait pour assurer la compatibilité multiplateforme.
— Iván Alegre

22

Mon équipe a rencontré ce problème lors de l'utilisation de Node avec React Native et PouchDB. Voici comment nous l'avons résolu ...

Tampon d'installation NPM:

$ npm install --save buffer

Assurez Buffer- vous que btoaet atobsont chargés en tant que globaux:

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
La commande new Buffer () dans votre code donne l'erreur suivante dans les versions plus récentes du nœud: [DEP0005] DeprecationWarning: Buffer () est déconseillé en raison de problèmes de sécurité et de convivialité. Veuillez utiliser les méthodes Buffer.alloc (), Buffer.allocUnsafe () ou Buffer.from () à la place.
— Rodrigo De Almeida Siqueira

8

J'ai trouvé que même si les cales des réponses ci-dessus fonctionnaient, elles ne correspondaient pas au comportement des implémentations des navigateurs de bureau btoa()et 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])));

Il s'avère que les Bufferinstances représentent / interprètent les chaînes encodées en UTF-8 par défaut . En revanche, dans Chrome de bureau, vous ne pouvez même pas saisir une chaîne contenant des caractères en dehors de la plage latin1 dansbtoa() , car cela lèvera une exception:Uncaught DOMException: Failed to execute 'btoa' on 'Window': The string to be encoded contains characters outside of the Latin1 range.

Par conséquent, vous devez définir explicitement le type de codage sur latin1pour que votre module d'interface Node.js corresponde au type de codage de Chrome de bureau:

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

dans le noeud v0.12.2 il n'y a pas de fonction
— Buffer.from

@Zibri Node v0.12.2 est ancien et a atteint sa fin de vie il y a deux ans . Buffer.from()est la façon recommandée d'utiliser l'API Buffer pour des raisons de sécurité (bien que ce lien clarifie les alternatives à celles Buffer.from()qui peuvent s'appliquer à Node v0.12.2).
— Jamie Birch

Je comprends cela, mais sur un appareil intégré, j'ai cette version.
— Zibri

J'exécute mon code dans Atom en utilisant le package de script github.com/rgbkrk/atom-script qui est une ancienne implémentation de node. En d'autres termes, il a également besoin d'une implémentation pour btoa, alors qu'il ne peut pas faire face à Buffer.from ().
— Shrimpy

4

J'ai un code partagé entre le serveur et le client et j'avais besoin d'une implémentation de btoa à l'intérieur. J'ai essayé de faire quelque chose comme:

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

mais le serveur écraserait avec:

ReferenceError: btoa n'est pas défini

while Buffern'est pas défini sur le client.

Je n'ai pas pu vérifier window.btoa (c'est un code partagé, tu te souviens?)

Je me suis donc retrouvé avec cette implémentation:

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

1

Je comprends que c'est un point de discussion pour une application de nœud, mais dans l'intérêt des applications JavaScript universelles s'exécutant sur un serveur de nœud, c'est ainsi que je suis arrivé à ce poste, je l'ai recherché pour une application de réaction universelle / isomorphe, j'ai été bâtiment, et le package a ababfonctionné pour moi. En fait, c'était la seule solution que je pouvais trouver qui fonctionnait, plutôt que d'utiliser la méthode Buffer également mentionnée (j'avais des problèmes de frappe).

(Ce package est utilisé par jsdom, qui à son tour est utilisé par le windowpackage.)

Pour en revenir à mon propos; sur cette base, peut-être que si cette fonctionnalité est déjà écrite en tant que package npm comme celui que vous avez mentionné, et possède son propre algorithme basé sur les spécifications W3, vous pouvez installer et utiliser le ababpackage plutôt que d'écrire votre propre fonction qui peut ou non être précis basé sur l'encodage.

--- MODIFIER ---

J'ai commencé à avoir des problèmes étranges aujourd'hui avec l'encodage (je ne sais pas pourquoi cela a commencé maintenant) avec le package abab. Il semble encoder correctement la plupart du temps, mais parfois sur le front-end, il n'encode pas correctement. J'ai passé beaucoup de temps à essayer de déboguer, mais base-64je suis passé au package comme recommandé, et cela a fonctionné immédiatement. Semble définitivement être à l'algorithme base64 de abab.


1

Même problème avec le plugin 'script' dans l'éditeur Atom, qui est une ancienne version de node, n'ayant ni btoa (), ni atob (), ni supportant le type de données Buffer. Le code suivant fait l'affaire:

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


Cela fonctionne grâce. Dans mon cas, j'utilise ChakraEngine qui ne semble pas supporter atob.
— Water


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

Voici une solution universelle concise pour le codage base64:

const nodeBtoa = (b) => Buffer.from(b).toString('base64');
export const base64encode = typeof btoa !== 'undefined' ? btoa : nodeBtoa;
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.