encodeURI 和 encodeURIComponent 都用于对字符串进行百分号编码,但它们面向的对象不同:

  • encodeURI:编码一个完整的 URI,同时尽量保留 URI 的结构符号。

  • encodeURIComponent:编码 URI 中的一个组成部分,例如查询参数的值。

所以,编码 https://example.com/a?x=1&y=2 时,两者结果不同是正常的。

一、先看编码结果

        
const url = "https://example.com/a?x=1&y=2";

console.log(encodeURI(url));
// https://example.com/a?x=1&y=2

console.log(encodeURIComponent(url));
// https%3A%2F%2Fexample.com%2Fa%3Fx%3D1%26y%3D2
        
      

encodeURI 编码后,URL 看起来还是一个完整的 URL,这是因为它保留了 URL 中用于分隔结构的字符,例如:

        
: / ? & =
        
      

而 encodeURIComponent 会把这些字符也编码掉。结果中的冒号、斜杠、问号、等号和 & 都变成了百分号编码。

因此,encodeURIComponent 的结果看起来不再像一个可直接使用的 URL。它表示的是“整个 URL 字符串作为一个数据片段”,而不是保留 URL 结构后的地址。

二、为什么需要两种方法?

URL 不只是普通字符串,它有自己的结构。例如:

        
https://example.com/search?q=JavaScript&sort=recent
        
      

可以拆成:

        
协议:       https:
主机名:     example.com
路径:       /search
参数分隔符: ?
参数:       q=JavaScript
参数分隔符: &
参数:       sort=recent
        
      

在这个结构里,?、&、=、/ 等字符可能具有特殊含义。如果把它们全部保留或全部编码,结果会完全不同。

encodeURI 适合处理整个 URI:尽可能保留这些结构符号。

encodeURIComponent 适合处理URI 的某一个值:将值中的结构符号也编码,避免它们被误认为 URL 的分隔符。

三、encodeURI 会保留哪些字符?

encodeURI 通常会保留 URL 中有结构意义的字符,包括:

        
; , / ? : @ & = + $ # -
        
      

例如:

        
encodeURI("https://example.com/search?q=hello world");
        
      

结果:

        
https://example.com/search?q=hello%20world
        
      

URL 的结构部分仍然保留,而空格被编码成 %20。

encodeURI 的一个重要限制

encodeURI 会保留 #,但 # 在 URL 中表示片段标识符。因此,字符串中的 # 可能会被浏览器当成 URL 片段的开始。

        
const url = "https://example.com/search#tag";

console.log(encodeURI(url));
// https://example.com/search#tag
        
      

如果 # 本来是某个参数值中的普通字符,就不应该直接依赖 encodeURI 来处理整个 URL。应当对参数值单独编码。

四、encodeURIComponent 会做什么?

encodeURIComponent 会编码 URI 中具有结构意义的分隔符,例如:

        
; , / ? : @ & = + $ #
        
      

例如:

        
const value = "https://example.com/a?x=1&y=2";

console.log(encodeURIComponent(value));
// https%3A%2F%2Fexample.com%2Fa%3Fx%3D1%26y%3D2
        
      

在这里,整个字符串被作为一个普通值处理。原有的 https://、? 和 & 不再作为 URL 结构符号存在。

五、最常见的用法:编码查询参数的值

假设要把用户输入放进查询参数:

        
const keyword = "JavaScript & 前端";

const url = "https://example.com/search?q=" + encodeURIComponent(keyword);

console.log(url);
// https://example.com/search?q=JavaScript%20%26%20%E5%89%8D%E7%AB%AF
        
      

这里应该使用 encodeURIComponent,因为 keyword 是参数值。

如果错误地使用 encodeURI:

        
const keyword = "JavaScript & sort=recent";

const url = "https://example.com/search?q=" + encodeURI(keyword);
        
      

& 和 = 会被保留,拼出来的内容可能被解释成额外的查询参数:

        
https://example.com/search?q=JavaScript%20&%20sort=recent
        
      

这样就可能改变 URL 的含义。

六、简单记忆

可以这样记:

处理完整 URL,考虑使用 encodeURI;处理 URL 中的某一个值,使用 encodeURIComponent。

示例:

        
const fullUrl = "https://example.com/search?q=hello world";

// 整个 URL
encodeURI(fullUrl);

// 参数值
encodeURIComponent("hello world");
        
      

不过,实际项目中,拼接查询参数时通常更推荐使用 URLSearchParams,避免手动处理编码和分隔符。

七、推荐做法:使用 URLSearchParams

        
const params = new URLSearchParams({
  q: "JavaScript & 前端",
  sort: "recent",
});

const url = `https://example.com/search?${params.toString()}`;

console.log(url);
// https://example.com/search?q=JavaScript+%26+%E5%89%8D%E7%AB%AF&sort=recent
        
      

URLSearchParams 会处理参数值的编码,并正确构造查询字符串。对于普通的查询参数场景,通常比手动拼接字符串更安全、清晰。

也可以基于 URL 对象构造地址:

        
const url = new URL("https://example.com/search");
url.searchParams.set("q", "JavaScript & 前端");
url.searchParams.set("sort", "recent");

console.log(url.toString());
        
      

八、空格编码:%20 与 +

encodeURI 和 encodeURIComponent 通常会把空格编码成:

        
%20
        
      

而 URLSearchParams 在序列化查询参数时,可能会把空格表示为:

        
+
        
      

例如:

        
new URLSearchParams({ q: "hello world" }).toString();
// q=hello+world
        
      

这两种形式常见于不同的 URL 编码场景。处理查询参数时,优先使用 URLSearchParams,不要为了统一格式而随意手动替换。

九、几个常见误区

1. 不要用 encodeURIComponent 编码整个 URL 后直接访问

        
const encoded = encodeURIComponent("https://example.com");
        
      

结果会变成:

        
https%3A%2F%2Fexample.com
        
      

这已经不是普通的 https://example.com URL 结构了。它更适合作为另一个 URL 的参数值,例如:

        
const redirectUrl = "https://example.com/login?next=" +
  encodeURIComponent("https://example.com/dashboard");
        
      

2. 不要重复编码

        
const once = encodeURIComponent("hello world");
// hello%20world

const twice = encodeURIComponent(once);
// hello%2520world
        
      

第二次编码时,% 被编码成了 %25,于是 %20 变成 %2520。这通常会导致数据恢复时出现问题。

3. 编码不等于安全过滤

URI 编码的目的是正确表示字符串,不是替代输入校验、权限检查或防止所有注入攻击。安全处理仍应结合具体使用场景完成。

总结

方法

处理对象

是否保留 URL 结构符号

常见用途

encodeURI

完整 URI

是

编码完整 URL 中需要编码的字符

encodeURIComponent

URI 的一个组成部分

否,更多分隔符会被编码

编码查询参数值、路径参数值等

简单来说,encodeURI("https://...") 编码后仍像一个 URL,是因为它保留了 URL 的结构字符;encodeURIComponent("https://...") 会把这些结构字符也编码,因此结果看起来像一整段普通数据。查询参数的值优先使用 URLSearchParams 或 encodeURIComponent。