Base64変換の基本API
ブラウザ環境では、データをBase64形式に変換・復元するための組み込み関数が提供されています。
window.btoa(): 8ビットのバイナリデータ(ASCII文字列)をBase64エンコードされた文字列に変換します。window.atob(): Base64エンコードされた文字列をデコードし、元のバイナリデータ(ASCII文字列)を復元します。
これらのメソッドは、データの安全な転送や保存時にバイナリデータをテキスト形式として扱うために頻繁に利用されます。
基本的な使用例
const originalText = "Welcome to JavaScript";
const base64Encoded = window.btoa(originalText);
console.log(base64Encoded); // "V2VsY29tZSB0byBKYXZhU2NyaXB0"
const base64Decoded = window.atob(base64Encoded);
console.log(base64Decoded); // "Welcome to JavaScript"
通信プロトコルとBase64の必要性
特定のネットワークプロトコルやレガシーなシステムでは、ASCIIコードの0〜31に含まれる制御文字をそのまま送信するとエラーが発生する場合があります。このような制約を回避し、データを安全にペイロードに含めるために、送信前にBase64エンコードを適用し、受信側でデコードを行うという手法が一般的です。
マルチバイト文字(Unicode)の扱いとエラー回避
JavaScriptの文字列(DOMString)はUTF-16で内部的に表現されています。そのため、日本語や絵文字など、8ビット(1バイト)のASCII範囲を超えるUnicode文字を直接 window.btoa() に渡すと、InvalidCharacterError(Character Out Of Range)が発生します。
解決策1: URIエンコーディングとの組み合わせ
最も手軽な回避策は、Base64エンコード前に文字列をURIエンコードし、デコード時にURIデコードを行う方法です。
/**
* Unicode文字列をBase64にエンコードする
* @param {string} text - 変換対象の文字列
* @returns {string} Base64エンコードされた文字列
*/
function encodeToBase64(text) {
const uriEncoded = encodeURIComponent(text);
const binaryString = uriEncoded.replace(/%([0-9A-F]{2})/g, (match, hex) => {
return String.fromCharCode(parseInt(hex, 16));
});
return window.btoa(binaryString);
}
/**
* Base64文字列をUnicode文字列にデコードする
* @param {string} base64Str - Base64エンコードされた文字列
* @returns {string} 復元されたUnicode文字列
*/
function decodeFromBase64(base64Str) {
const binaryString = window.atob(base64Str);
const uriEncoded = Array.from(binaryString)
.map(char => '%' + ('00' + char.charCodeAt(0).toString(16)).slice(-2))
.join('');
return decodeURIComponent(uriEncoded);
}
const multibyteText = "こんにちは世界 🌍";
const encodedMultibyte = encodeToBase64(multibyteText);
console.log(encodedMultibyte);
const decodedMultibyte = decodeFromBase64(encodedMultibyte);
console.log(decodedMultibyte); // "こんにちは世界 🌍"
解決策2: TextEncoderとTypedArrayの活用
よりモダンで堅牢なアプローチとして、TextEncoder と TextDecoder APIを使用してUTF-8のバイト配列に変換し、それをBase64化する手法があります。大規模なデータやバイナリファイルを扱う場合は、base64-js のような専用ライブラリや、TypedArrayを直接処理するポリフィルを採用することが推奨されます。
インタラクティブな変換ツールの実装
以下は、ユーザーの入力に対してエンコードとデコードを実行するシンプルなUIコンポーネントの実装例です。インラインイベントハンドラを避け、モダンなイベントリスナーとエラーハンドリングを導入しています。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>Base64変換ツール</title>
<style>
.result-box { margin-top: 10px; padding: 10px; border: 1px solid #ccc; min-height: 20px; word-break: break-all; }
.error { color: #d32f2f; font-weight: bold; }
</style>
</head>
<body>
<h1>Base64エンコーダー / デコーダー</h1>
<input type="text" id="userInput" placeholder="テキストを入力してください" style="width: 300px; padding: 5px;">
<button id="btnEncode">エンコード</button>
<button id="btnDecode">デコード</button>
<h3>結果:</h3>
<div id="outputArea" class="result-box"></div>
<script>
const inputField = document.getElementById('userInput');
const outputArea = document.getElementById('outputArea');
const btnEncode = document.getElementById('btnEncode');
const btnDecode = document.getElementById('btnDecode');
function handleEncode() {
const rawText = inputField.value;
if (!rawText) {
showError('テキストが入力されていません。');
return;
}
try {
const result = encodeToBase64(rawText);
displayResult(result);
} catch (e) {
showError('エンコード中にエラーが発生しました: ' + e.message);
}
}
function handleDecode() {
const base64Text = inputField.value;
if (!base64Text) {
showError('テキストが入力されていません。');
return;
}
try {
const result = decodeFromBase64(base64Text);
displayResult(result);
} catch (e) {
showError('デコード中にエラーが発生しました。有効なBase64文字列を入力してください。');
}
}
function displayResult(message) {
outputArea.textContent = message;
outputArea.className = 'result-box';
}
function showError(message) {
outputArea.textContent = message;
outputArea.className = 'result-box error';
}
btnEncode.addEventListener('click', handleEncode);
btnDecode.addEventListener('click', handleDecode);
// encodeToBase64 と decodeFromBase64 関数がスコープ内に定義されている前提
</script>
</body>
</html>