JavaScript での Base64 エンコード/デコード: btoa()、atob()、Unicode
JavaScript での Base64 エンコーディングとデコーディング
JavaScript には、Base64 文字列をエンコードおよびデコードするための組み込みの方法がいくつかあります。ブラウザアプリケーションを構築している場合でも、Node.js サーバーを構築している場合でも、JSON、HTML、URL などのテキストベースの形式でバイナリデータを扱うには、Base64 の操作方法を理解することが不可欠です。
ブラウザでの btoa() と atob() の使用
ブラウザの JavaScript で Base64 を扱うための 2 つの中心的な関数は、btoa() と atob() です。これらの関数名は古い命名規則に従っています — btoa は「binary to ASCII」の略で、atob は「ASCII to binary」の略です。これらは何十年もの間、すべての主要ブラウザでサポートされてきました。
btoa() でのエンコーディング
const originalString = 'Hello, world!';
const encoded = btoa(originalString);
console.log(encoded);
// Output: SGVsbG8sIHdvcmxkIQ==
atob() でのデコーディング
const base64String = 'SGVsbG8sIHdvcmxkIQ==';
const decoded = atob(base64String);
console.log(decoded);
// Output: Hello, world!
どちらの関数も、Latin-1 文字(各文字が 1 バイトで表される)のみを含む文字列で動作します。これは重要な制限であり、次に説明します。
Unicode 文字と非 ASCII 文字の処理
よくある落とし穴: btoa() は、絵文字、中国語文字、アクセント付き文字など、Latin-1 の範囲外の文字を含む文字列が渡されるとエラーをスローします。
btoa('Hello 你好');
// Error: The string to be encoded contains characters outside of the Latin-1 range.
Unicode 文字列をエンコードするには、まず文字列をバイトに変換してから、そのバイトをエンコードする必要があります。最新のアプローチでは、TextEncoder と TextDecoder API を使用します:
function unicodeToBase64(str) {
const bytes = new TextEncoder().encode(str);
const binaryString = String.fromCharCode(...bytes);
return btoa(binaryString);
}
function base64ToUnicode(base64) {
const binaryString = atob(base64);
const bytes = Uint8Array.from(binaryString, (c) => c.charCodeAt(0));
return new TextDecoder().decode(bytes);
}
// Usage
const encoded = unicodeToBase64('Hello 你好 🚀');
console.log(encoded);
// Output: SGVsbG8g5L2g5aW9IPCfj4A=
const decoded = base64ToUnicode(encoded);
console.log(decoded);
// Output: Hello 你好 🚀
古い手法では encodeURIComponent と decodeURIComponent を使用しますが、TextEncoder/TextDecoder のアプローチの方が堅牢で、推奨される最新のソリューションです。
バイナリデータのエンコーディング(ArrayBuffer)
fetch や FileReader などの API からファイル、画像、生のバイナリデータを扱う場合、通常は ArrayBuffer または Uint8Array を取得します。これを Base64 に変換する方法は次のとおりです:
function arrayBufferToBase64(buffer) {
const bytes = new Uint8Array(buffer);
let binaryString = '';
for (let i = 0; i < bytes.length; i++) {
binaryString += String.fromCharCode(bytes[i]);
}
return btoa(binaryString);
}
function base64ToArrayBuffer(base64) {
const binaryString = atob(base64);
const bytes = new Uint8Array(binaryString.length);
for (let i = 0; i < binaryString.length; i++) {
bytes[i] = binaryString.charCodeAt(i);
}
return bytes.buffer;
}
ブラウザでファイルを Base64 に変換する
FileReader を使用して、ユーザーが選択したファイルを Base64 データ URL に変換する完全な例を次に示します:
function fileToBase64(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = () => resolve(reader.result);
reader.onerror = () => reject(new Error('Failed to read file'));
reader.readAsDataURL(file);
});
}
// Usage with a file input
document.querySelector('input[type="file"]').addEventListener('change', async (e) => {
const file = e.target.files[0];
try {
const dataUrl = await fileToBase64(file);
console.log(dataUrl); // data:image/png;base64,iVBORw0KGgo...
} catch (err) {
console.error('Conversion failed:', err);
}
});
Node.js での Base64 の使用
Node.js は Base64 操作用の Buffer クラスを提供しており、ブラウザの btoa/atob よりも柔軟です。Buffer クラスは Unicode を含むエンコードとデコードを自動的に処理し、複数のエンコード形式をサポートします。
基本的なエンコーディングとデコーディング
// Encode a string to Base64
const encoded = Buffer.from('Hello, world!').toString('base64');
console.log(encoded);
// Output: SGVsbG8sIHdvcmxkIQ==
// Decode a Base64 string back to text
const decoded = Buffer.from(encoded, 'base64').toString('utf-8');
console.log(decoded);
// Output: Hello, world!
Node.js での Unicode サポート
ブラウザの btoa() とは異なり、Node.js の Buffer は Unicode をシームレスに処理します:
const encoded = Buffer.from('Hello 你好 🚀').toString('base64');
console.log(encoded);
// Output: SGVsbG8g5L2g5aW9IPCfj4A=
const decoded = Buffer.from(encoded, 'base64').toString('utf-8');
console.log(decoded);
// Output: Hello 你好 🚀
ファイルの読み取りと Base64 へのエンコーディング
const fs = require('fs');
// Read a file and encode it to Base64
const buffer = fs.readFileSync('image.png');
const base64 = buffer.toString('base64');
const dataUrl = `data:image/png;base64,${base64}`;
Node.js での Base64url エンコーディング
Node.js 15.7.0 以降ではネイティブの Base64url エンコーディングをサポートしており、+ を - に、/ を _ に置き換えてパディングを省略します:
const encoded = Buffer.from('Hello, world!').toString('base64url');
console.log(encoded);
// Output: SGVsbG8sIHdvcmxkIQ (no padding)
const decoded = Buffer.from(encoded, 'base64url').toString('utf-8');
console.log(decoded);
// Output: Hello, world!
パフォーマンスに関する考慮事項
大規模なデータの場合、Base64 操作を繰り返すと遅くなる可能性があります。いくつかのヒントを紹介します:
- Unicode 文字列では手動変換ではなく
TextEncoder/TextDecoderを使用する - Node.js では、
Buffer.from()は高度に最適化されています — 手動実装よりも優先してください - 必要な場合を除き、大きなファイルを Base64 に変換しないようにする(ストリーミングを検討する)
- 大規模なデータセットでは、メインスレッドのブロッキングを避けるために、ブラウザで
BlobとFileReaderの使用を検討する
Base64 エンコーディングをオンラインで試す
無料のオンライン Base64 エンコーダとデコーダを使って、ブラウザで直接エンコードとデコードを試してみましょう。コーディングは不要です — テキストを貼り付けるかファイルをアップロードするだけで、Base64 の結果が即座に得られます。