Node.jsが「btoa is not defined」エラーをスローする


230

私のnode.jsアプリケーションでは、npm install btoa-atobクライアント側のjavascriptにネイティブであるbtoa()およびatob()関数を使用できるようにするために、何らかの理由でノードに含まれていませんでした。新しいディレクトリは、node.modulesフォルダーに表示されます。このフォルダー自体は、app.jsと一緒にルートにあります。次に、ルートにあるpackage.jsonファイルに依存関係としてbtoa-atobを必ず追加しました。

ただし、何らかの理由で、まだ機能しません。

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

^コンソールに「SGVsbG8gV29ybGQh」を出力するはずですが、代わりに「btoaが定義されていません」というエラーが表示されます。

正しくインストールできませんでしたか?私は何を見落としましたか?

回答:


537

「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文字では機能しません(つまり、Node.jsとブラウザー間でbase64を交換する場合)。これを機能させるには、入力テキストを「バイナリ」としてマークする必要があります。

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
イヴァンありがとう、私はこれに何時間も費やしたでしょう...あなたの答えは受け入れられるべきものです!
— Pawel

IvánAlegre「バイナリ」エンコーディングを使用しないでください。そうした場合Buffer.from('Hélló wórld!!').toString('base64')-それはあなたを与えるだろうSOlsbPMgd/NybGQhIQ==戻って適切に非ASCII文字列に変換することができます。
— TotalAMD

1
@TotalAMDそれは仕事のブラウザまたはその逆へのNode.jsからbase64での交換はありません
— イバン・アレグレ

3
base64でエンコードを比較し、同じプラットフォームでデコードしています。Chrome to ChromeおよびNode to Node。バイナリなしでノード10でエンコードすると、になりますSMOpbGzDsyB3w7NybGQhIQ==。これをブラウザでデコードすると、表示されますHélló wórld!!。このバイナリは、クロスプラットフォームの互換性を保証するのに最適です。
— イバン・アレグレ

22

私のチームは、React NativeとPouchDBでNodeを使用しているときにこの問題に遭遇しました。これが私たちがそれを解決した方法です...

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()は、nodeの新しいバージョンで次のエラーを発生させます。代わりに、Buffer.alloc()、Buffer.allocUnsafe()、またはBuffer.from()メソッドを使用してください。
— ロドリゴデアルメイダシケイラ

8

上記の回答からのシムは機能しましたが、デスクトップブラウザのbtoa()and の実装の動作と一致しなかったことがわかりました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.

したがって、Node.jsシムがデスクトップChromeのエンコードタイプと一致するように、エンコードタイプを明示的にに設定する必要がありlatin1ます。

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

@Zibri Node v0.12.2は古く、2年前にサポートが終了しています。セキュリティ上の理由から、Buffer APIを使用するためBuffer.from()の推奨される方法です(ただし、そのリンクはBuffer.from()、Node v0.12.2に適用される可能性のある代替手段を明確にします)。
— ジェイミーバーチ

私はそれを理解していますが、組み込みデバイスにはそのバージョンがあります。
— Zibri、

ノードの古い実装であるスクリプトパッケージgithub.com/rgbkrk/atom-scriptを使用して、Atomでコードを実行しています。つまり、Btoaの実装も必要ですが、Buffer.from()には対応できません。
— Shrimpy

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メソッドを使用するのではなく(typescriptの問題があった)ことでした。

(このパッケージはによって使用されjsdom、次にwindowパッケージによって使用されます。)

私の要点に戻ります。これに基づいて、おそらくこの機能がすでに述べたようなnpmパッケージとして記述されていて、W3仕様に基づく独自のアルゴリズムを持っている場合は、abab独自の関数を記述せずにパッケージをインストールして使用できます。エンコーディングに基づいて正確です。

--- 編集 ---

今日、パッケージでのエンコーディングで奇妙な問題が発生し始めました(なぜ今それが始まっているのかわかりません)abab。ほとんどの場合、正しくエンコードされているようですが、フロントエンドで正しくエンコードされない場合があります。デバッグに長い時間を費やしましたがbase-64、推奨どおりパッケージに切り替えましたが、すぐに動作しました。間違いなくのbase64アルゴリズムにあるように見えましたabab。


1

Atoエディターの 'script'プラグインに同じ問題があります。これは古いバージョンのノードであり、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=='));


これでうまくいきました。私の場合、私はatobをサポートしていないように見えるChakraEngineを使用しています。
— 水


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;
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.