调试7 分钟阅读
如何修复 JavaScript 中的 "URI Malformed" 错误
通过实用的解决方案,排查并修复 JavaScript 中常见的 "URIError: URI malformed" 错误。
理解 URIError: URI Malformed 错误
当你尝试解码一个包含无效百分号编码序列的字符串时,JavaScript 就会抛出 URIError: URI malformed 错误。当 decodeURI() 或 decodeURIComponent() 遇到格式错误的编码字符时,就会抛出该错误。
常见原因
1. 孤立的百分号
一个百分号(%)如果后面没有紧跟恰好两位十六进制数字,就是无效的。例如,%、%G 或 %2(不完整)都会导致这个错误。
// 以下这些都会抛出 URIError
decodeURIComponent('%'); // 孤立的 %
decodeURIComponent('%2'); // 不完整的序列
decodeURIComponent('%GH'); // 无效的十六进制数字
decodeURIComponent('100%'); // 末尾的 %,后面没有十六进制数字
2. 无效的 UTF-8 序列
当百分号编码的字节无法构成有效的 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 以便调试