深入理解 encodeURI / encodeURIComponent 与 decodeURI / decodeURIComponent 的区别

195 阅读3分钟

一、概念

在前端开发中,URL 编码是常见操作。JavaScript 提供了四个相关方法:

  • encodeURI:对整个 URI 进行编码。
  • encodeURIComponent:对 URI 片段(组件)进行编码。
  • decodeURI:对 encodeURI 编码的结果进行解码。
  • decodeURIComponent:对 encodeURIComponent 编码的结果进行解码。

简而言之:

  • encodeURI / decodeURI 用在完整 URL 层级。
  • encodeURIComponent / decodeURIComponent 用在 URL 中的参数或单独片段。

二、原理

  1. URL 编码的目的
    URL 只能使用 ASCII 字符(安全子集),因此像空格、中文、特殊符号(如 ?&=)必须转换为合法形式。
    比如:空格 → %20中 → %E4%B8%AD
  2. encodeURI 的编码规则
    保留了 URL 中合法的结构符号:
  • 不会转义 : / ? # & = 等(这些在 URL 中有语义作用)。
  • 会转义空格、中文、非法符号。
  1. encodeURIComponent 的编码规则
    它比 encodeURI 更严格:
  • 几乎所有非字母数字字符都会被转义,包括 ? & = 等。
  • 因此适合用于参数值的编码,避免与 URL 本身结构冲突。
  1. 解码函数
  • decodeURI 只会解码 encodeURI 编码的字符串。
  • decodeURIComponent 更“彻底”,可以解码参数中的转义内容。

三、对比

方法适用范围保留字符示例
encodeURI整个 URL: / ? # & = 等结构符号encodeURI("https://a.com?q=测试") → "https://a.com?q=%E6%B5%8B%E8%AF%95"
encodeURIComponentURL 片段 / 参数不保留任何结构符号encodeURIComponent("测试&demo") → "%E6%B5%8B%E8%AF%95%26demo"
decodeURI解码 encodeURI 的结果保留结构符号decodeURI("https://a.com?q=%E6%B5%8B%E8%AF%95") → "https://a.com?q=测试"
decodeURIComponent解码 encodeURIComponent 的结果更彻底decodeURIComponent("%E6%B5%8B%E8%AF%95%26demo") → "测试&demo"

四、实践

1. 错误示例

// 错误:encodeURIComponent 编码整个 URL
let url = "https://example.com/page?q=hello world";
let wrong = encodeURIComponent(url);
console.log(wrong);
// 输出: "https%3A%2F%2Fexample.com%2Fpage%3Fq%3Dhello%20world"
// 问题:整个 URL 都被转义,浏览器无法识别

2. 正确用法

// 正确:encodeURI 用于整个 URL
let url = "https://example.com/page?q=hello world";
let correct = encodeURI(url);
console.log(correct);
// 输出: "https://example.com/page?q=hello%20world"

// 正确:encodeURIComponent 用于参数值
let param = "hello world&测试";
let encodedParam = encodeURIComponent(param);
let finalUrl = `https://example.com/page?q=${encodedParam}`;
console.log(finalUrl);
// 输出: "https://example.com/page?q=hello%20world%26%E6%B5%8B%E8%AF%95"

五、拓展

  1. 为什么要区分 URI 与 URI Component?

    • URI(统一资源标识符)由多个部分组成,如协议、主机名、路径、查询参数。
    • 如果把整个 URL 都用 encodeURIComponent,结构符号也被转义,URL 失效。
    • 所以规范上才有这两个不同层级的方法。
  2. 配合使用场景

    • 构造 API 请求时,encodeURIComponent 是必需的,否则特殊字符会导致参数错位。
    • 解析 URL 时,必须选择和编码阶段对应的解码函数,否则会解码不完整或报错。
  3. 与 escape/unescape 的区别

    • 旧方法 escape / unescape 已弃用,不支持完整的 UTF-8 编码。
    • 应始终使用 encodeURI 系列。

六、潜在问题

  1. 双重编码问题

    • 如果某个参数已经被编码,再次用 encodeURIComponent,会出现 %25(即 % 的转义)。
    • 解决:只在拼接 URL 时编码一次。
  2. 解码不匹配

    • decodeURI 解码 encodeURIComponent 的结果时,可能失败或解码不完整。

    • 必须成对使用:

      • encodeURIdecodeURI
      • encodeURIComponentdecodeURIComponent
  3. 兼容性问题

    • 现代浏览器已统一支持这四个方法,但在部分旧代码库里仍存在 escape / unescape,需要注意迁移。

✅ 总结一句:

  • 整个 URL → encodeURI
  • 参数值 → encodeURIComponent
  • 解码时严格配对使用

本文部分内容借助 AI 辅助生成,并由作者整理审核。