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, 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 () 메소드를 대신 사용하십시오.
— 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.