Node.js에서“btoa is not defined”오류 발생


230

내 node.js 응용 프로그램 npm install btoa-atob에서 클라이언트 측 자바 스크립트에 고유하지만 어떤 이유로 노드에 포함되지 않은 btoa () 및 atob () 함수를 사용할 수 있도록했습니다. 새 디렉토리는 node.modules 폴더에 나타 났으며 app.js와 함께 루트에 있습니다. 그런 다음 루트에있는 package.json 파일에서 btoa-atob를 종속성으로 추가했는지 확인했습니다.

그러나 어떤 이유로 든 여전히 작동하지 않습니다.

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

^ "SGVsbG8gV29ybGQh"를 콘솔에 출력해야하지만 대신 "btoa is not defined"오류가 발생합니다.

제대로 설치하지 않았습니까? 무엇을 간과 했습니까?

답변:


537

'btoa-atob'모듈은 프로그래밍 인터페이스를 내 보내지 않으며 명령 줄 유틸리티 만 제공합니다.

Base64로 변환해야하는 경우 버퍼를 사용하여 수행 할 수 있습니다.

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

역전 (복호하는 내용이 utf8 문자열이라고 가정) :

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

참고 : 노드 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
당신에게 Ivan 감사합니다, 나는 이것에 몇 시간을 보냈을 것입니다 ... 당신은 받아 들여야하는 대답해야합니다!
Pawel

Iván Alegre 그냥 '이진'인코딩을 사용하지 마십시오. 그렇게 Buffer.from('Hélló wórld!!').toString('base64')하면 SOlsbPMgd/NybGQhIQ==— ASCII가 아닌 문자열로 올바르게 변환 할 수 있습니다.
TotalAMD

1
@TotalAMD이 작업 브라우저 또는 viceversa에에 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, btoaatob전역으로로드됩니다

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 () 메소드를 대신 사용하십시오.
Rodrigo De Almeida Siqueira

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를 위해서는 :

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에 적용될 수있는 대안을 명확하게 설명하지만 ).
Jamie Birch

이해하지만 임베디드 장치에는 해당 버전이 있습니다.
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 방법을 사용하는 대신 (유형 스크립트 문제가 있음) 작동하는 유일한 해결책이었습니다.

(이 패키지는에서 사용하며 jsdom, 패키지 에서 사용됩니다 window.)

내 요점으로 돌아 가기; 이를 기반으로, 아마도이 기능이 이미 언급 한 것과 같은 npm 패키지로 작성되었고 W3 사양을 기반으로 자체 알고리즘을 가지고 있다면 설치 및 사용할 수 있습니다abab 패키지를 수 있습니다. 인코딩에 따라 정확합니다.

--- 편집 ---

package와 함께 인코딩 (지금 시작하는 이유를 확실하지 않음)과 관련하여 오늘 이상한 문제가 발생했습니다 abab. 대부분의 경우 올바르게 인코딩하는 것처럼 보이지만 때로는 프런트 엔드에서 잘못 인코딩됩니다. 디버깅에 오랜 시간을 소비했지만 base-64권장대로 패키지 로 전환 했으며 곧바로 작동했습니다. 확실히의 base64 알고리즘에 해당하는 것 같습니다 abab.


1

btoa () 또는 atob ()이없는 이전 버전의 노드 인 Atom 편집기의 'script'플러그인과 동일한 문제가 아니며 버퍼 데이터 유형을 지원하지 않습니다. 다음 코드는 트릭을 수행합니다.

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.