日本語

開発者ツール · URL エンコーダーとデコーダー

URIError: URI の形式が正しくありません — decodeURIComponent がスローする理由とその修正方法

· 仕組み

URLエンコーディング JavaScript エラー処理

パーセント記号の後に無効な 16 進数が続くと、URIError 例外が発生します
オリジナル ToolAcre ベクトル イラスト

decodeURIComponent は、パーセント記号の後に 2 つの 16 進数が続かない場合、またはデコードされたバイトが有効でない場合 (UTF-8) にスローされます。この投稿では、それをトリガーする入力と防御的にデコードする方法を示します。

クラッシュしたパーセント記号 — 「100% off」が decodeURIComponent を中断する理由

フォームは割引コード「100% オフ」を収集します。 JavaScript は、これを URL デコーダーの decodeURIComponent に渡します。この関数は URIError: URI の形式が正しくありませんをスローします。パーセント記号の後に 2 つの 16 進数が続きません。これはパーセント エンコーディング ルールに完全に違反します。 decodeURIComponent は、すべての % が %20 や %C3 のようなトリプレットを開始することを期待します。単独の % は構文エラーであり、実行が直ちに停止され、エラーがスローされます。

このエラーを安全に捕捉すると、アプリケーションのクラッシュを完全に防ぐことができます。 URL は、ユーザー入力、リダイレクト、QR コード、電子メールから到着します。タイプミスが頻繁に起こります。 URIError を含むクラッシュ レポートは、どこを迅速に調査すべきかを示します。防御的なデコードによりアプリケーションの実行が継続され、エラー ログがデバッグに役立ちます。

2 種類の失敗 - 不正な形式の 16 進エスケープと無効な UTF-8 バイト シーケンス

decodeURIComponent は、正確に 2 つの状況でスローします。 1 つ目: 不正な形式のエスケープ シーケンス。パーセントの後に 2 つの 16 進数が続かないもの (0-9、A ~ F、a ~ f)。例: %ZZ、%2, %2g。 2 番目: %E9 のような有効なトリプレットが無効な UTF-8 バイトにデコードされます。 1つ目はフォーマットエラーです。 2 つ目は意味上のエラーです。どちらもすぐに実行をスローして停止します。

UTF-8 にはバイト シーケンスに関する厳密な規則があります。バイト 0x80 ~ 0xFF は、マルチバイト シーケンスでのみ表示されます。単一の %E9 を単独で有効な UTF-8 にすることはできません。この孤立したバイトによりエラーが発生します。フォーマットエラーは明らかです。意味上のエラーは微妙ですが、同様に現実的です。どちらの場合も、製品コードでの try/catch 処理が必要です。

従来のシングルバイトエンコーディング - %E9 のみがスローされるが、%C3%A9 が存続する場合

混乱は Web 標準の歴史から生じています。古いページでは、UTF-8 の代わりに Latin-1 が使用されていました。ラテン語では、1, %E9 は é を表します。最新のブラウザは UTF-8 のみを使用します。 UTF-8 は é を %C3%A9 としてエンコードします。最新のデコーダは UTF-8 を期待し、%E9 を不正な形式として拒否します。これは正しい動作です。このエラーは、ソース データに問題があることを示します。

最新のコンセンサス: どこでも UTF-8。 URL 標準では UTF-8 が指定されています。現在のすべてのブラウザは UTF-8 を使用します。古いシステムで %E9 が発生した場合は、エラーを捕捉し、生の文字列にフォールバックします。最新のコードでは Latin-1 としてデコードしないでください。データの出所を調査します。

3 つの入力、3 つのエラー メッセージ - 同じ壊れた文字列に対するエンジンの違い

ブラウザ エンジンは不正な入力を一貫して拒否しますが、ワード エラーの拒否方法は異なります。 Chrome が「不正な URI」を報告します。 Firefox が「不正な URI シーケンス」を報告します。 Safari は「未定義をオブジェクトに変換できません」と報告します。 3 つのエンジンはすべて同じ入力を拒否します。正確なメッセージの文言は、異なるエンジンまたはバージョン間で標準化されていません。コード ロジックをガイドするためにエラー テキストに依存しないでください。

プログラムの決定のためにエラー メッセージを文字列照合しないでください。常に URIError をタイプ別にキャッチします。 decodeUrl 関数は decodeURIComponent をラップし、一貫したコード INVALID_PERCENT_ENCODING を提供します。これにより、問題の正確な位置が指定されます。エンジンの文言のバリエーションに依存しないため、複数のランタイムで機能します。このアプローチは、より信頼性が高く、保守可能です。

例外を安全に読み取る — try/catch, 検証とフォールバック パターン

最も単純な防御パターン: try/catch. で decodeURIComponent をラップする スローされる場合は、生の文字列または置換文字を使用します。これにより、不正な入力によるクラッシュが防止されます。クエリ値については、URL エンコードされた形式を表示します。ユーザー向けテキストの場合は、置換文字を挿入します。これにより、不正な入力によってアプリケーションが中断されることがなくなり、安定性が維持されます。

速度と安全性を確保するために正規表現を使用して事前検証します。デコードする前に、入力に有効な %XX トリプレットのみが含まれていることを確認してください。パターン /%[0-9A-Fa-f]{2}/g は有効なエスケープを捕捉します。一致しないものは無効です。フォーマット エラーは、明らかなゴミの場合はすぐに失敗します。 UTF-8 エラーには try/catch. が必要です。これにより、エラーに対する包括的な防御保護が提供されます。

サイレントエラーはバグを隠す — ブラインドデコードが壊れたエンコードと同じくらい危険な理由

微妙なリスク: デコーダーはスローせずに、間違ったテキストを静かに生成します。非推奨の unescape を使用する古いコードでは、メモリ内に無効な UTF-8 が残ります。 UTF-8 を厳密に検証するシステムに到達するまで、テキストは画面上では問題なく表示されます。最新のコードは、静かに破損するのではなく、スローされます。例外は、ダウンストリームに広がるサイレントなデータ破損よりも明確で安全です。

ユーザー入力が不正な形式であると仮定します。常に呼び出しをラップします。デバッグ用に元の入力でエラーをログに記録します。すべての % が有効であると想定しないでください。タイプミスや切り捨てにより、不完全なエスケープが作成されます。論理エラーではなくデータエラーとして扱います。防御的なコードは不正な入力に正常に耐え、システムの信頼性を維持します。

実際のツールがスキップするもの — サーバー側のフレームワークの動作とエラー回復

サーバー フレームワークは、不正なエンコードをブラウザよりも寛容に処理します。 Ruby、Python、および PHP は、URL 内の無効なエスケープを処理するための構成を提供します。一部の置換文字は自動的に置換されます。黙ってバイトをドロップする人もいます。 JavaScript のように例外をスローするものもあります。実際の動作は、開発者が選択したフレームワークと構成設定によって異なります。

この記事では、ブラウザーの JavaScript の動作のみを説明します。値がサーバー API から到着した場合、サーバーは送信前にすでにエラーをデコードまたはスキップしています。サーバーはクライアントよりも寛容な場合があります。 API コントラクトを作成するときは、値が生であるか、事前デコードされているかを指定します。 URL クエリ文字列はパーセントエンコードされて到着する必要があります。 JSON は事前にデコードされて到着する可能性があります。

早期に検証 — URL エンコーダとデコーダを使用して疑わしい文字列を最初にチェックします

疑わしい URL を decodeURIComponent に渡す前に、URL エンコーダとデコーダに貼り付けます。このツールは正確なエンコーディングを表示し、不正なエスケープを検出し、アプリケーションをクラッシュさせることなくエラーを説明します。 %ZZ、%E9、100% を使用してテストし、さまざまなエラーとその正確なエラー メッセージを確認します。これには数秒かかり、自信が生まれます。

早期に検証し、エラーを適切に検出し、何が壊れたかを記録します。防御的なデコーダとテスト ツールにより、アプリケーションの実行とデバッグが可能になります。 URL エンコーダとデコーダは、「不正な URI」をすぐに使用できる実用的な情報に変換します。このパターンを独自のデコーダに適用して、運用環境での復元力と保守性を高めます。