Node.js BufferでのBase64

Node.jsでBuffer、ストリーム、グローバルbtoa/atob関数を使ったBase64エンコード・デコードをマスター。ファイル処理、文字列操作、パフォーマンスのコツを解説します。

Language

詳細な説明

Node.jsは初期バージョンから利用可能な Buffer クラスを通じて堅牢なBase64サポートを提供します。Node.js 16からはグローバルな btoa()atob() 関数も利用できますが、サーバーサイドコードでは Buffer が引き続き推奨されるアプローチです。

BufferによるBase64の基本的なエンコードとデコード:

// String to Base64
const encoded = Buffer.from("Hello, World!").toString("base64");
// "SGVsbG8sIFdvcmxkIQ=="

// Base64 to string
const decoded = Buffer.from("SGVsbG8sIFdvcmxkIQ==", "base64").toString("utf-8");
// "Hello, World!"

URL-safe Base64:

// Encode as Base64url
const urlSafe = Buffer.from("Hello, World!").toString("base64url");
// "SGVsbG8sIFdvcmxkIQ"  (no padding, - and _ instead of + and /)

// Decode Base64url
const fromUrlSafe = Buffer.from("SGVsbG8sIFdvcmxkIQ", "base64url").toString("utf-8");

"base64url" エンコーディングオプションはNode.js 14で追加され、文字の置換とパディング除去を自動的に処理します。

ファイルのエンコードとデコード:

const fs = require("fs");

// File to Base64
const fileBase64 = fs.readFileSync("image.png").toString("base64");

// Base64 to file
fs.writeFileSync("output.png", Buffer.from(fileBase64, "base64"));

大きなファイルのストリーミング処理: メモリに読み込めないほど大きなファイルには、組み込みのtransformを使ったストリームを利用します:

const { Transform } = require("stream");
const fs = require("fs");

// Custom Base64 encoding stream
class Base64Encode extends Transform {
  constructor() {
    super();
    this.remainder = Buffer.alloc(0);
  }
  _transform(chunk, encoding, callback) {
    const combined = Buffer.concat([this.remainder, chunk]);
    const usable = combined.length - (combined.length % 3);
    this.push(combined.slice(0, usable).toString("base64"));
    this.remainder = combined.slice(usable);
    callback();
  }
  _flush(callback) {
    if (this.remainder.length > 0) {
      this.push(this.remainder.toString("base64"));
    }
    callback();
  }
}

fs.createReadStream("large-file.bin")
  .pipe(new Base64Encode())
  .pipe(fs.createWriteStream("output.b64"));

Buffer vs btoa/atob:

  • Buffer はバイナリデータをネイティブに扱い、複数のエンコーディング(utf-8base64base64urlhexlatin1)をサポート
  • btoa()/atob() はブラウザと同様にLatin-1文字列のみを扱い、コードポイント255を超える文字でエラーが発生
  • Buffer はストリーミングをサポートし、大きなデータに対してよりメモリ効率的
  • サーバーサイドコードでは Buffer を使用。btoa()/atob() はブラウザの動作に合わせる必要があるアイソモーフィックコードでのみ使用

よくある間違い: デコード時にエンコーディングを指定せずに Buffer.from(string) を使用すること。デフォルトのエンコーディングは "utf-8" であり、入力をBase64データではなくUTF-8文字列として解釈してしまいます。デコード時は必ず第二引数に "base64" を指定してください。

ユースケース

Base64エンコードされたJSONペイロードでファイルアップロードを受信し、BufferでデコードしてクラウドストレージにストリーミングするNode.jsマイクロサービスを構築する場合に使用します。

試してみる — Base64 Encoder

フルツールを開く