【JavaScript】日本語をBase64形式にエンコード・デコードする方法|btoa・TextEncoder・Buffer.from・FileReader対応

JavaScriptのbtoa()関数はASCII文字専用のため、日本語などのマルチバイト文字をそのまま渡すとエラーになります。

この記事では、encodeURIComponentTextEncoderBuffer.from(Node.js)など、日本語を安全にBase64エンコード・デコードする方法を網羅的に解説します。データURIスキームへの応用やファイルのBase64化まで、実務で使えるテクニックをすべてカバーしています。

この記事で学べること

  • Base64エンコードとは何か(基本概念と用途)
  • btoa() / atob() の基本とASCII限定の問題
  • encodeURIComponent + btoa で日本語をBase64化する方法
  • TextEncoder / TextDecoder を使ったモダンな変換方法(推奨)
  • Node.js での Buffer.from() を使った方法
  • データURIスキームへの応用
  • FileReader でファイルをBase64化する方法
  • 汎用ユーティリティ関数の実装
  • パフォーマンスとセキュリティの注意点
スポンサーリンク

Base64エンコードとは

Base64は、バイナリデータを64種類のASCII文字(A-Z、a-z、0-9、+、/)とパディング文字(=)で表現するエンコード方式です。

項目 内容
使用文字 A-Z, a-z, 0-9, +, /(計64文字)+ パディング =
変換単位 3バイト → 4文字(6ビットずつ区切る)
サイズ増加 元データの約1.33倍(33%増加)
主な用途 メール添付(MIME)、データURI、API通信、JWT、Cookie

ポイント:Base64は暗号化ではなく、エンコードです。誰でもデコードできるため、パスワードや機密情報の保護には使えません。

btoa() / atob() の基本

JavaScriptにはBase64エンコード・デコード用の組み込み関数が用意されています。

関数 役割 引数 戻り値
btoa() Binary to ASCII バイナリ文字列 Base64文字列
atob() ASCII to Binary Base64文字列 バイナリ文字列

ASCII文字のエンコード・デコード

btoa / atob の基本
// エンコード(文字列 → Base64)
const encoded = btoa("Hello World");
console.log(encoded);  // "SGVsbG8gV29ybGQ="

// デコード(Base64 → 文字列)
const decoded = atob("SGVsbG8gV29ybGQ=");
console.log(decoded);  // "Hello World"

実行結果

SGVsbG8gV29ybGQ=
Hello World

日本語でbtoa()がエラーになる理由

btoa()は各文字のコードポイントが0x00〜0xFF(Latin-1の範囲)の文字列のみ受け付けます。日本語などのマルチバイト文字はこの範囲を超えるため、InvalidCharacterErrorが発生します。

日本語でbtoa()を使うとエラー
try {
  const result = btoa("こんにちは");
} catch (e) {
  console.log(e.name);     // "InvalidCharacterError"
  console.log(e.message);  // btoa に渡された文字列にLatin-1の範囲外の文字が含まれています
}

実行結果

InvalidCharacterError: Failed to execute 'btoa' on 'Window':
The string to be encoded contains characters outside of the Latin1 range.

注意:「あ」のコードポイントはU+3042(12354)で、Latin-1の上限0xFF(255)を大幅に超えています。そのためbtoa("あ")はエラーになります。

方法1: encodeURIComponent + btoa で日本語をBase64化

最もシンプルな方法は、encodeURIComponent()で日本語をパーセントエンコーディングに変換してからbtoa()に渡す方法です。

エンコード

encodeURIComponent + btoa
const text = "こんにちは世界";

// ステップ1: encodeURIComponent で日本語をパーセントエンコーディング
const percentEncoded = encodeURIComponent(text);
console.log(percentEncoded);
// "%E3%81%93%E3%82%93%E3%81%AB%E3%81%A1%E3%81%AF%E4%B8%96%E7%95%8C"

// ステップ2: btoa() でBase64エンコード
const base64 = btoa(percentEncoded);
console.log(base64);
// "JUUzJTgxJTkzJUUzJTgyJTkzJUUzJTgxJUFCJUUzJTgxJUExJUUzJTgxJUFGJUU0JUI4JTk2JUU3JTk1JThD"

実行結果

%E3%81%93%E3%82%93%E3%81%AB%E3%81%A1%E3%81%AF%E4%B8%96%E7%95%8C
JUUzJTgxJTkzJUUzJTgyJTkzJUUzJTgxJUFCJUUzJTgxJUExJUUzJTgxJUFGJUU0JUI4JTk2JUU3JTk1JThD

デコード

atob + decodeURIComponent
const base64Str = "JUUzJTgxJTkzJUUzJTgyJTkzJUUzJTgxJUFCJUUzJTgxJUExJUUzJTgxJUFGJUU0JUI4JTk2JUU3JTk1JThD";

// ステップ1: atob() でBase64デコード
const percentStr = atob(base64Str);

// ステップ2: decodeURIComponent でパーセントエンコーディングをデコード
const original = decodeURIComponent(percentStr);
console.log(original);  // "こんにちは世界"

実行結果

こんにちは世界

注意:この方法は手軽ですが、パーセントエンコーディングを経由するためBase64文字列が長くなるデメリットがあります。UTF-8バイト列を直接Base64化する次の方法が推奨です。

方法2: TextEncoder / TextDecoder を使った方法(推奨)

モダンブラウザで最も推奨される方法は、TextEncoderでUTF-8バイト列に変換し、各バイトをString.fromCharCode()でLatin-1文字列に変換してからbtoa()に渡す方法です。

エンコード(日本語 → Base64)

TextEncoder を使ったBase64エンコード(推奨)
function utf8ToBase64(str) {
  // TextEncoder で UTF-8 バイト列(Uint8Array)に変換
  const encoder = new TextEncoder();
  const uint8Array = encoder.encode(str);

  // 各バイトを Latin-1 文字に変換
  const binaryStr = Array.from(uint8Array)
    .map(byte => String.fromCharCode(byte))
    .join("");

  // btoa() で Base64 エンコード
  return btoa(binaryStr);
}

const base64 = utf8ToBase64("こんにちは世界");
console.log(base64);
// "44GT44KT44Gr44Gh44Gv5LiW55WM"

実行結果

44GT44KT44Gr44Gh44Gv5LiW55WM

デコード(Base64 → 日本語)

TextDecoder を使ったBase64デコード
function base64ToUtf8(base64) {
  // atob() で Base64 デコード → バイナリ文字列
  const binaryStr = atob(base64);

  // バイナリ文字列 → Uint8Array
  const uint8Array = new Uint8Array(
    [...binaryStr].map(char => char.charCodeAt(0))
  );

  // TextDecoder で UTF-8 バイト列を文字列に変換
  const decoder = new TextDecoder();
  return decoder.decode(uint8Array);
}

const original = base64ToUtf8("44GT44KT44Gr44Gh44Gv5LiW55WM");
console.log(original);  // "こんにちは世界"

実行結果

こんにちは世界

ポイント:この方法はencodeURIComponent方式と比べてBase64文字列が短くなります。UTF-8バイト列を直接変換するため、無駄なパーセントエンコーディングが不要だからです。

方法1と方法2の出力比較

同じ日本語文字列をエンコードした場合、出力サイズにどれだけ差があるか比較してみましょう。

エンコード結果の比較
const text = "こんにちは世界";

// 方法1: encodeURIComponent + btoa
const method1 = btoa(encodeURIComponent(text));
console.log(`方法1: ${method1}`);
console.log(`長さ: ${method1.length}文字`);

// 方法2: TextEncoder + btoa
const encoder = new TextEncoder();
const method2 = btoa(Array.from(encoder.encode(text)).map(b => String.fromCharCode(b)).join(""));
console.log(`方法2: ${method2}`);
console.log(`長さ: ${method2.length}文字`);

実行結果

方法1: JUUzJTgxJTkzJUUzJTgyJTkzJUUzJTgxJUFCJUUzJTgxJUExJUUzJTgxJUFGJUU0JUI4JTk2JUU3JTk1JThD
長さ: 84文字
方法2: 44GT44KT44Gr44Gh44Gv5LiW55WM
長さ: 28文字
方法 Base64の長さ 特徴
encodeURIComponent + btoa 84文字 パーセントエンコーディング分が冗長
TextEncoder + btoa(推奨) 28文字 UTF-8バイト列を直接変換、効率的

方法3: Node.js での Buffer.from() を使った方法

Node.js環境ではBufferオブジェクトを使うことで、非常にシンプルにBase64変換が行えます。

エンコード

Node.js – Buffer.from() でエンコード
// Node.js 環境
const text = "こんにちは世界";

// エンコード: 文字列 → Base64
const base64 = Buffer.from(text, "utf-8").toString("base64");
console.log(base64);
// "44GT44KT44Gr44Gh44Gv5LiW55WM"

デコード

Node.js – Buffer.from() でデコード
const base64Str = "44GT44KT44Gr44Gh44Gv5LiW55WM";

// デコード: Base64 → 文字列
const original = Buffer.from(base64Str, "base64").toString("utf-8");
console.log(original);  // "こんにちは世界"

実行結果

44GT44KT44Gr44Gh44Gv5LiW55WM
こんにちは世界

ポイント:Node.jsのBuffer.from()は内部でUTF-8エンコーディングを自動処理するため、TextEncoder方式と同じ結果が得られます。Node.js環境では最も簡潔な方法です。

URL安全なBase64(Base64URL)エンコード

標準のBase64は+/を含むため、URLのクエリパラメータやファイル名に使うと問題が起きます。Base64URLはこれらを-_に置換した形式です。

Base64URLエンコード / デコード
// Base64URL エンコード
function toBase64URL(str) {
  const encoder = new TextEncoder();
  const bytes = encoder.encode(str);
  const binStr = Array.from(bytes).map(b => String.fromCharCode(b)).join("");
  return btoa(binStr)
    .replace(/\+/g, "-")
    .replace(/\//g, "_")
    .replace(/=+$/, "");  // パディング除去
}

// Base64URL デコード
function fromBase64URL(base64url) {
  let base64 = base64url
    .replace(/-/g, "+")
    .replace(/_/g, "/");

  // パディング復元
  while (base64.length % 4) base64 += "=";

  const binStr = atob(base64);
  const bytes = new Uint8Array([...binStr].map(c => c.charCodeAt(0)));
  return new TextDecoder().decode(bytes);
}

// 使用例
const encoded = toBase64URL("日本語テスト+/=");
console.log(encoded);  // URL安全な文字列

const decoded = fromBase64URL(encoded);
console.log(decoded);  // "日本語テスト+/="
形式 使用文字 パディング 用途
標準 Base64 A-Z, a-z, 0-9, +, / あり(=) メール、データURI
Base64URL A-Z, a-z, 0-9, , _ なし JWT、URLパラメータ、ファイル名

データURIスキームへの応用

データURIは、外部ファイルを参照せずにデータをインラインで埋め込むための仕組みです。Base64エンコードしたデータをHTMLやCSSに直接記述できます。

テキストをデータURIに変換

テキストのデータURI化
function textToDataURI(text, mimeType = "text/plain") {
  const encoder = new TextEncoder();
  const bytes = encoder.encode(text);
  const base64 = btoa(Array.from(bytes).map(b => String.fromCharCode(b)).join(""));
  return `data:${mimeType};charset=utf-8;base64,${base64}`;
}

// 日本語HTMLをデータURIに変換
const html = "<h1>こんにちは</h1><p>日本語コンテンツ</p>";
const dataURI = textToDataURI(html, "text/html");
console.log(dataURI);

// iframeに表示する例
// document.querySelector("iframe").src = dataURI;

SVGをデータURIに変換

SVGのBase64データURI化
const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100">
  <circle cx="50" cy="50" r="40" fill="#3b82f6"/>
  <text x="50" y="55" text-anchor="middle" fill="white">日本語</text>
</svg>`;

const svgDataURI = textToDataURI(svg, "image/svg+xml");

// CSSの背景画像として使用
// element.style.backgroundImage = `url(${svgDataURI})`;

// img要素のsrcとして使用
// document.querySelector("img").src = svgDataURI;

ファイルをBase64化する方法(FileReader)

ブラウザで画像やPDFなどのファイルをBase64エンコードするには、FileReaderreadAsDataURL()メソッドを使います。

基本的なファイルのBase64変換

FileReader でファイルをBase64化
// inputタグ: <input type="file" id="fileInput">

function fileToBase64(file) {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();

    reader.onload = () => {
      // readAsDataURL の結果: "data:image/png;base64,iVBOR..."
      const base64 = reader.result.split(",")[1]; // Base64部分のみ
      resolve(base64);
    };

    reader.onerror = () => reject(reader.error);
    reader.readAsDataURL(file);
  });
}

// 使用例
document.getElementById("fileInput").addEventListener("change", async (e) => {
  const file = e.target.files[0];
  const base64 = await fileToBase64(file);
  console.log(`ファイル名: ${file.name}`);
  console.log(`サイズ: ${file.size} bytes`);
  console.log(`Base64: ${base64.substring(0, 50)}...`);
});

画像をBase64に変換してプレビュー表示

画像のBase64プレビュー
function previewImage(file, imgElement) {
  const reader = new FileReader();

  reader.onload = () => {
    // readAsDataURL はそのまま src に設定可能
    imgElement.src = reader.result;
  };

  reader.readAsDataURL(file);
}

// 使用例
const input = document.getElementById("fileInput");
const preview = document.getElementById("preview");

input.addEventListener("change", (e) => {
  const file = e.target.files[0];
  if (file && file.type.startsWith("image/")) {
    previewImage(file, preview);
  }
});

Base64エンコード・デコードのユーティリティ関数

実務で使いやすいように、エンコード・デコード関数をまとめたユーティリティを紹介します。

Base64ユーティリティ(コピペで使えます)
const Base64Util = {

  /** 文字列 → Base64(日本語対応) */
  encode(str) {
    const bytes = new TextEncoder().encode(str);
    const binStr = Array.from(bytes, b => String.fromCharCode(b)).join("");
    return btoa(binStr);
  },

  /** Base64 → 文字列(日本語対応) */
  decode(base64) {
    const binStr = atob(base64);
    const bytes = new Uint8Array([...binStr].map(c => c.charCodeAt(0)));
    return new TextDecoder().decode(bytes);
  },

  /** 文字列 → Base64URL(日本語対応) */
  encodeURL(str) {
    return this.encode(str)
      .replace(/\+/g, "-")
      .replace(/\//g, "_")
      .replace(/=+$/, "");
  },

  /** Base64URL → 文字列(日本語対応) */
  decodeURL(base64url) {
    let base64 = base64url.replace(/-/g, "+").replace(/_/g, "/");
    while (base64.length % 4) base64 += "=";
    return this.decode(base64);
  },

  /** ファイル → Base64(Promise) */
  fromFile(file) {
    return new Promise((resolve, reject) => {
      const reader = new FileReader();
      reader.onload = () => resolve(reader.result.split(",")[1]);
      reader.onerror = () => reject(reader.error);
      reader.readAsDataURL(file);
    });
  }
};

// 使用例
console.log(Base64Util.encode("日本語テスト"));   // Base64文字列
console.log(Base64Util.decode("5pel5pys6Kqe44OG44K544OI")); // "日本語テスト"
console.log(Base64Util.encodeURL("URL安全+/テスト")); // Base64URL文字列

実行結果

5pel5pys6Kqe44OG44K544OI
日本語テスト
VVJM5a6J5YWoKy/jg4bjgrnjg4g

パフォーマンスと注意点

サイズ増加

Base64エンコードすると、データサイズは約33%増加します。大きなファイルのBase64化は慎重に検討してください。

サイズ増加の確認
function checkSizeIncrease(text) {
  const encoder = new TextEncoder();
  const originalBytes = encoder.encode(text).length;
  const base64Str = Base64Util.encode(text);
  const base64Bytes = base64Str.length;

  console.log(`元のサイズ: ${originalBytes} bytes`);
  console.log(`Base64サイズ: ${base64Bytes} bytes`);
  console.log(`増加率: ${((base64Bytes / originalBytes - 1) * 100).toFixed(1)}%`);
}

checkSizeIncrease("Hello World");        // ASCII
checkSizeIncrease("こんにちは世界");  // 日本語

実行結果

元のサイズ: 11 bytes
Base64サイズ: 16 bytes
増加率: 45.5%
元のサイズ: 21 bytes
Base64サイズ: 28 bytes
増加率: 33.3%

セキュリティに関する注意

注意:Base64は暗号化ではありません。以下の点に注意してください。

  • Base64でエンコードしたデータは誰でもデコードできます
  • パスワードや個人情報の保護には暗号化(AES等)を使ってください
  • APIキーやトークンをBase64で「隠す」のはセキュリティ対策になりません
  • HTTP Basic認証のBase64は盗聴に対して無力です(HTTPS必須)

大きなデータの処理

大きなデータのチャンク処理
// 大きなBlob/FileをチャンクでBase64化(メモリ効率が良い)
async function largeFileToBase64(file, chunkSize = 1024 * 1024) {
  const chunks = [];
  let offset = 0;

  while (offset < file.size) {
    const slice = file.slice(offset, offset + chunkSize);
    const arrayBuffer = await slice.arrayBuffer();
    const bytes = new Uint8Array(arrayBuffer);
    chunks.push(...bytes);
    offset += chunkSize;
  }

  const binStr = chunks.map(b => String.fromCharCode(b)).join("");
  return btoa(binStr);
}

ブラウザ互換性

API Chrome Firefox Safari Edge Node.js
btoa() / atob() 1+ 1+ 3+ 12+ 16+
TextEncoder 38+ 19+ 10.1+ 79+ 11+
TextDecoder 38+ 19+ 10.1+ 79+ 11+
FileReader 6+ 3.6+ 6+ 12+
Buffer.from() 5.10+

ポイント:TextEncoder/TextDecoderはIE非対応ですが、モダンブラウザでは問題なく使用できます。IEサポートが必要な場合はencodeURIComponent方式を使ってください。

まとめ

JavaScriptで日本語をBase64エンコード・デコードする方法を紹介しました。最後に各方法の特徴を比較します。

方法 環境 効率 おすすめ度
encodeURIComponent + btoa ブラウザ 低(文字列が長い) レガシー対応時
TextEncoder + btoa ブラウザ 推奨
Buffer.from() Node.js Node.jsでは最適
FileReader ブラウザ ファイル変換に特化

この記事のポイント

  • btoa()はASCII専用。日本語を直接渡すとInvalidCharacterErrorになる
  • ブラウザではTextEncoder + btoaの組み合わせが最も効率的(推奨)
  • Node.jsではBuffer.from(str, “utf-8”).toString(“base64”)が最もシンプル
  • URLで使う場合はBase64URL形式(+/=-_)に変換する
  • Base64はエンコードであり暗号化ではない。機密情報の保護には使えない
  • Base64化するとデータサイズが約33%増加する点に注意