调试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 以便调试

相关文章

试用我们的免费工具