デバッグ7 分で読めます
JavaScript で発生する「URI Malformed」エラーの解決方法
JavaScript でよく発生する「URIError: URI malformed」エラーの原因を突き止め、実践的な解決策で修正する方法を解説します。
URIError: URI Malformed エラーを理解する
URIError: URI malformed エラーは、不正な percent-encoding のシーケンスを含む文字列をデコードしようとしたときに JavaScript で発生します。このエラーは、decodeURI() や decodeURIComponent() が不正な形式のエンコード文字に遭遇した際にスローされます。
よくある原因
1. 単独のパーセント記号
直後に 16 進数 2 桁が続かないパーセント記号(%)は不正です。たとえば、%、%G、%2(不完全)などはいずれもこのエラーを引き起こします。
// これらは URIError をスローします
decodeURIComponent('%'); // 単独の %
decodeURIComponent('%2'); // 不完全なシーケンス
decodeURIComponent('%GH'); // 不正な 16 進数
decodeURIComponent('100%'); // 末尾に 16 進数のない %
2. 不正な UTF-8 シーケンス
percent-encoding されたバイト列が有効な UTF-8 文字シーケンスを構成しない場合、デコーダはそれを文字列に変換できません。これは、データが破損している場合や、異なる文字エンコーディングでエンコードされていた場合に発生することがあります。
3. 二重エンコード
二重エンコードは、すでにエンコード済みの文字列をさらにエンコードしたときに発生します。たとえば、%20(エンコードされたスペース)は %2520 にエンコードされます。元の文字列をデコードしようとすると、シーケンスが不正になることがあります。
解決方法
解決策 1: try-catch を使う
function safeDecode(str) {
try {
return decodeURIComponent(str);
} catch (e) {
// デコードに失敗した場合は元の文字列を返す
console.warn('Failed to decode:', str, e.message);
return str;
}
}
解決策 2: デコード前に検証する
function isValidEncodedURI(str) {
try {
decodeURIComponent(str);
return true;
} catch {
return false;
}
}
function fixMalformedURI(str) {
// 単独の % を %25(エンコードされたパーセント記号)に置換する
return str.replace(/%(?![0-9A-Fa-f]{2})/g, '%25');
}
解決策 3: 二重エンコードを防ぐ
function smartEncode(str) {
// まずデコードを試みる。成功すれば、その文字列は
// すでにエンコード済みである
try {
const decoded = decodeURIComponent(str);
// デコードで文字列が変化した場合、それはエンコードされていた
if (decoded !== str) {
return str; // すでにエンコード済みなのでそのまま返す
}
} catch {
// 有効なエンコード文字列ではないのでエンコードする
}
return encodeURIComponent(str);
}
予防のためのベストプラクティス
- ユーザー入力や外部から取得した URL をデコードする際は、必ず try-catch を使う
- 処理する前に URL を検証する
- 値を二重エンコードしないよう注意する
- 可能な場合は URL および URLSearchParams API を使う。これらはエンコードを正しく処理してくれる
- エンコードする前にクエリ文字列の値をサニタイズする
- デバッグのために不正な URL をログに記録する