開発者ツール · Base64 エンコーダーおよびデコーダー
atob と btoa は何を表しており、なぜラテン語しか理解できないのか - 1
· 背景
base64 JavaScript ユニコード
atob および btoa は Netscape からのもので、名前は「ASCII からバイナリ」および「バイナリから ASCII」を意味します。この記事では、それらがどこから来たのか、WHATWG 標準でどのように定義されているのか、そしてなぜ Unicode を学習しなかったのかについて説明します。
タイプミスのように見える関数名 — 名前が引き起こす混乱と 1 行の答え
atob および btoa は、1990 年代に Netscape に導入された JavaScript 組み込み関数です。名前は略語です。btoa は binary to ASCII を表し、atob は ASCII to binary を表します。名前はその時代と設計を反映しています。バイナリがより現代的な Uint8Array や Buffer ではなく、バイト値の文字列 (0-255) を意味していた時代に構築されました。名前に対してよく与えられるニーモニックは、観察可能な規約ほど重要ではありません。1 つの関数はバイナリ文字列を Base64 にマップし、もう 1 つはそれを逆にします。このリポジトリには、元の命名決定が文書化されていないため、この記事では、ブラウザの歴史をソースとして民間伝承を提示することを避けています。
関数はバイナリ文字列を想定しています。各文字のコード単位は、1 バイトを表す 0 ~ 255 の範囲内である必要があります。 255 より上のコード単位を持つ文字 (ラテン語 1 以外の絵文字やアクセント付き文字など) を渡すと、関数は InvalidCharacterError をスローするか、サイレントに不正な出力を生成します。 btoa (バイナリから ASCII) は、バイナリ文字列を Base64 にエンコードします。
名前が示唆するものとバイト文字列契約が実際に証明するもの
入力は、各文字がバイトである文字列である必要があります (コード単位 0-255)。 btoa(hello) は、ASCII バイトを Base64 としてエンコードし、aGVsbG8= を返します。文字 e-acute を含む btoa は機能するように見えます。これは、事前に作成された Latin-1 文字 e-acute (U+00E9) のコード単位が 233 であり、これは 0 ~ 255 内にあるためです。ただし、btoa は、e-acute が生成する UTF-8 バイト 0xC3 0xA9 ではなく、単一バイト 0xE9 としてエンコードします。型付き配列が通常のバイト コンテナになる前は、JavaScript API はコード単位がバイトを表す文字列を使用していました。 btoa は 255 を超えるコード単位を拒否するため、そのモデルは表示されたままになります。これらのファイルでは、製品の正確な年表は確立されていません。障害境界は、実行可能なテストによって確立されます。
このサイレント破損はエラーよりも危険です。結果は問題ないように見えますが、間違っています。 atob (ASCII からバイナリへ) は、base64 をバイナリ文字列にデコードします。 atob(aGVsbG8=) は hello を返します。出力はバイナリ文字列で、各文字のコード単位は 0 ~ 255 で、1 バイトを表します。これを適切な Unicode テキストに変換したい場合は、バイトを UTF-8 として解釈し、TextDecoder でデコードする必要があります。
従来のバイナリ文字列モデル - 未検証のブラウザ履歴要求なしで観察可能な動作
ASCII の場合、この追加の手順は不要ですが (ASCII は UTF-8 のサブセットです)、非 ASCII バイトの場合は必須です。 atob はその解釈を行いません。生のバイトをバイナリ文字列として返します。
WHATWG 標準 (Web API の現存標準) は、HTML 仕様で atob と btoa を定義します。この定義には、atob 用の寛容な Base64 デコード アルゴリズムが含まれています。このアルゴリズムは空白をスキップし、不足しているパディングを受け入れ、実際の Base64 (改行を含む MIME ラップされた Base64 を含む) をデコード可能にします。 ToolAcre は、ブラウザ デコーダを呼び出す前に、空白、URL セーフな句読点、欠落しているパディングを正規化します。次に、返されたコードユニットを Uint8Array にコピーし、致命的な UTF-8 デコーダーを適用します。この組み合わせにより、寛容な Base64 構文と厳密なテキスト解釈が分離されます。
この実装の現在の動作 - 許容アルファベット正規化と厳密な UTF-8 テキスト デコード
関数のシグネチャは変更されていませんが、関数の動作の権限は標準定義にあります。 atob と btoa が Latin-1 のみを受け入れるのはなぜですか? 1990 年代に設計されたとき、JavaScript にはバイトを直接表す方法がなかったからです (Uint8Array や ArrayBuffer はありませんでした)。関数にバイトを渡す唯一の方法は、各文字が 1 バイトを表す文字列として渡すことでした。
これはバイナリ文字列と呼ばれ、最新の標準では混乱を招きます。 JavaScript 文字列は Unicode テキストであり、バイトのシーケンスではありません。設計ではこの 2 つが混同されています。各コード単位が 0 ~ 255 である文字列はバイナリ文字列です。名前は時代を反映しています。btoa の ASCII は文字通り ASCII テキストの 7 ビットを意味しますが、実装では任意のバイト (0-255) を受け入れます。 btoa に Unicode モードを直接追加すると、長年のバイト文字列規約が変更され、互換性が危険になります。レビューされたソースでは、代わりにエンコード前に TextEncoder が作成されます。この記事ではその構成を検証できます。リポジトリに記録されていない標準委員会の動機に関する主張は省略されています。
作業例: スペースとパディングが欠落している文字列での forgiving-base64 のトレース — 厳密なデコーダーが拒否するものを atob が受け入れるもの
最新の代替案では、バイナリ文字列モデルが回避されています。 Encoding API は、テキストを UTF-8 バイトに変換する TextEncoder と、UTF-8 バイトをテキストに戻す TextDecoder を提供します。
Base64 エンコードとデコードは、文字列 (atob と btoa) と型付き配列の両方の HTML 仕様で指定されるようになりました。 Base64 エンコーダおよびデコーダ ツールは、atob および btoa の周囲で TextEncoder および TextDecoder を使用するため、Latin-1 の制限なしで Unicode テキストを安全にエンコードおよびデコードできます。正規化によって空白が削除され、必要なブロック長が復元されるため、スペースのある値または埋め込まれていない値は成功します。クリーンアップされた長さが 1 を残す値は、atob の前に拒否されます。この区別は、ここでの「寛容」が何を意味するかを示しています。回復可能な形式は受け入れられますが、構造的に不可能な入力は受け入れられません。
新しい標準は型付き配列の Base64 で動作します - 現在のブラウザーのサポートを確認するための注記とともに定性的に説明されています
btoa で Unicode を処理するには、最初にテキストを UTF-8 バイトにエンコードする必要があります。古い回避策は btoa(unescape(encodeURIComponent(text))) でした。これは混乱を招きますが機能します。encodeURIComponent は UTF-8 バイトをパーセント エンコードし、unescape はトリプレットを文字に変換し、btoa は結果のバイナリ文字列をエンコードします。これは機能しますが、非推奨の関数に依存しているため、読みにくいです。最新のコードでは、TextEncoder(text).map(byte => String.fromCharCode(byte)) を使用し、その後に btoa を使用するか、またはそれを使用して Uint8Array に直接変換し、Encoding API を使用する必要があります。
Atob は自動的にテキストを提供しません。それはあなたにバイナリを与えます。 atob(Y2Fmw6kg8J+YgA==) は、caf-accent と絵文字を使用して UTF-8 でエンコードされたテキストのバイトを含むバイナリ文字列を返します。テキストを回復するには、バイナリ文字列を Uint8Array に変換し、TextDecoder(utf-8) に渡します。 Base64 エンコーダおよびデコーダ ツールはこれを自動的に行います。テキストを貼り付けると、それが UTF-8 バイトにエンコードされてから、base64 にエンコードされます。型付き配列 Base64 API はブラウザー間で進化していますが、このソースではそれらを使用していません。依存するものには、最新の互換性チェックとフォールバック計画が必要です。 ToolAcre の明示的なバイト配列変換は引き続き検査可能であり、現在のテスト スイートでカバーされています。
型付き配列の代替手段は進化しています - 代替手段に依存する前に現在のブラウザのサポートを確認してください
Base64 を貼り付けると、UTF-8 バイトにデコードされてからテキストにデコードされます。中間のバイナリ文字列ステップは、1990 年代の API の実装の詳細であるため、非表示になっています。 atob と btoa を理解すると、レガシー コードをデバッグしたり、バイナリ文字列を渡す古い API を操作したりするのに役立ちます。ほとんどの新しいコードでは、バイナリ文字列モデルを完全に回避する必要があります。
Base64 をエンコードまたはデコードする必要がある場合、Base64 エンコーダおよびデコーダ ツールは Unicode を正しく処理します。 API を構築している場合は、Uint8Array または型付き配列ビューを受け入れるか、base64 が UTF-8 であるか Latin-1 であるかを明確に文書化してください。 TextEncoder を使用せずに非 ASCII テキストで btoa を使用するコードをレビューすると、それはバグであり、出力は間違ったバイトをエンコードします。ノード バッファーと非ブラウザー ランタイムは、異なる API と受け入れルールを定義します。それらは意図的に除外されています。この記事の主張は、ブラウザーのプリミティブと apps/dev, に実装されたラッパーに関するものであり、すべての環境における atob または btoa という名前のすべての関数に関するものではありません。
要点: バイト文字列コントラクトを持つ 2 つの 1990 年代関数 — Base64 エンコーダーとデコーダーが UTF-8 ステップを回避してアクセント、CJK、および絵文字のラウンドトリップを行う方法
atob と btoa という名前は、1990 年代のコンピューティング特有の成果物です。最新の命名はbase64Encodeとbase64Decodeとなり、APIはUint8Arrayまたは明示的なエンコーディング宣言を持つ文字列を受け入れます。ただし、atob と btoa は下位互換性のためにブラウザーに残ります。それらの意味 (およびできないこと) を理解すると、Unicode テキストをエンコードする際のサイレント破損を回避するのに役立ちます。
Base64 エンコーダおよびデコーダ ツールはギャップを埋めます。最新のコードに必要な UTF-8 および Base64 言語を話します。堅牢なパターンは構成的なものです。テキストを UTF-8 バイトにエンコードし、バイトをバイナリ文字列コントラクトに変換してから、btoa を呼び出します。 atob 周りの手順を逆にします。アクセント、CJK 文字、絵文字を試してから、デコードされたテキストが元のすべてのコード ポイントと一致することを要求します。