btoa()はコード単位が1バイトの範囲に入るバイナリ文字列を受け取ります。UTF-8変換は自動ではありません。日本語、韓国語、ヒンディー語、多くの絵文字はInvalidCharacterErrorの原因になります。明示的にUTF-8バイトへ変換してください。
Unicodeをエンコード・デコードする
TextEncoderでテキストをバイト列にします。下のコードはbtoaの前に小さい単位で処理し、大きな入力で関数の引数上限を超えることを避けます。復元ではatobのバイト値をTextDecoderでUTF-8として読みます。fatalオプションは不正なバイトをエラーにします。
元の文字列に戻るか確認する
안녕하세요 😀は7JWI64WV7ZWY7IS47JqUIPCfmIA=になります。復元時は空白や絵文字まで同じになる必要があります。例のリンクには決められた公開データの名前だけを使い、利用者の入力をURLに含めません。Decodexは最大5 MBのUTF-8テキストをブラウザー内で処理します。
エラーが発生した段階を調べる
atobのエラーはBase64文字、パディング、接頭辞の問題が考えられます。TextDecoderのエラーは、有効なBase64でもバイナリや別の文字コードを示す場合があります。Node.jsではBuffer.from(text, "utf8").toString("base64")を使えますが、寛容なデコード処理は入力検証の代わりにはなりません。
この例を変換する
// Browser JavaScript: text → UTF-8 bytes → Base64.
function utf8ToBase64(text) {
const bytes = new TextEncoder().encode(text);
let binary = '';
for (let i = 0; i < bytes.length; i += 8192) {
binary += String.fromCharCode(...bytes.subarray(i, i + 8192));
}
return btoa(binary);
}
// Accept standard Base64 or Base64URL, with complete or omitted padding.
function base64ToUtf8(value) {
let normalized = value.replace(/\s/g, '').replace(/-/g, '+').replace(/_/g, '/');
if (!/^[A-Za-z0-9+/]*={0,2}$/.test(normalized) ||
normalized.length % 4 === 1 ||
(normalized.includes('=') && normalized.length % 4 !== 0)) {
throw new Error('Invalid Base64 characters, length or padding');
}
normalized += '='.repeat((4 - normalized.length % 4) % 4);
const binary = atob(normalized);
const bytes = Uint8Array.from(binary, character => character.charCodeAt(0));
return new TextDecoder('utf-8', { fatal: true }).decode(bytes);
}
const text = '안녕하세요 😀';
const encoded = utf8ToBase64(text);
console.log(encoded); // 7JWI64WV7ZWY7IS47JqUIPCfmIA=
console.log(base64ToUtf8(encoded)); // 안녕하세요 😀
よくある質問
atobだけで日本語が読めますか?
いいえ。戻り値はバイナリ文字列です。値をUint8Arrayに移し、TextDecoder("utf-8")で読みます。古いunescape()に依存する方法より明示的なバイト変換を使ってください。
