encodeURIComponent vs encodeURI 到底选哪个

· 约 3 分钟 🔗 URL 编解码

拼 URL 这种”五分钟搞定”的事,结果测试环境 OK、生产环境参数丢一半——八成是选错了编码函数。encodeURIencodeURIComponentescape 三个长得像的函数做的事完全不同。

三个函数对同一组字符的行为

先看对比表:

字符escapeencodeURIencodeURIComponent
空格%20%20%20
+++%2B
&%26&%26
===%3D
?%3F?%3F
#%23#%23
///%2F
:%3A:%3A
@@@%40
中文”你”%u4F60%E4%BD%A0%E4%BD%A0

三个关键差异

  1. escape 中文输出 %uXXXX——非标准,很多服务器不识别
  2. encodeURI 保留 URL 结构字符(: / ? & = # @
  3. encodeURIComponent 全部编码

什么时候用谁

encodeURIComponent:编码参数 value

const name = '张三&李四';
const url = `/api/user?name=${encodeURIComponent(name)}`;
// /api/user?name=%E5%BC%A0%E4%B8%89%26%E6%9D%8E%E5%9B%9B

如果这里用 encodeURI& 不会被编码,后端以为 name=张三、多出一个 李四 参数——数据错位。

encodeURI:编码整个 URL(兜底)

const url = 'https://example.com/搜索?q=你好';
fetch(encodeURI(url));
// https://example.com/%E6%90%9C%E7%B4%A2?q=%E4%BD%A0%E5%A5%BD

这里 :/? 作为结构字符要保留原样,所以不能用 encodeURIComponent——那会把整个 URL 变成一个字符串。

永远不用 escape

历史包袱,写新代码就当它不存在。

编码拼 URL 的正确顺序

常见错误:先拼后编码——把结构字符一起编了。

错误

encodeURIComponent(`/api?name=${name}`)
// %2Fapi%3Fname%3D张三   ← 整个 URL 被编成一个字符串

正确

`/api?name=${encodeURIComponent(name)}`
// /api?name=%E5%BC%A0%E4%B8%89

口诀:结构先拼好,value 再编码

URLSearchParams:更现代的做法

手动拼字符串容易漏。用内置 API:

const params = new URLSearchParams();
params.set('name', '张三&李四');
params.set('age', 30);
const url = `/api/user?${params.toString()}`;
// /api/user?name=%E5%BC%A0%E4%B8%89%26%E6%9D%8E%E5%9B%9B&age=30

自动处理编码、多值(append 可加同名参数)、+ 空格表单规则。

注意URLSearchParams 对空格用 +(遵循 form-urlencoded),不是 %20。对大多数服务端没问题,但如果后端严格按 RFC 3986 解析路径,要手动 .replace(/\+/g, '%20')

路径段里的特殊情况

URL 路径里的斜杠是分隔符,文件名含 / 需要编码:

const filename = 'report/2026Q1.pdf';
const url = `/files/${encodeURIComponent(filename)}`;
// /files/report%2F2026Q1.pdf

如果直接拼,后端会把它当成两段路径。

反过来,如果是子路径,不要编码:

const path = '/reports/2026/Q1';
const url = `/api${path}`;        // 对
const url = `/api${encodeURIComponent(path)}`;  // 错,斜杠变 %2F

解码对称性

编码用 encodeURIComponent,解码就用 decodeURIComponent。编码用 encodeURI,解码用 decodeURI。混用在大多数情况下没事,但遇到包含已编码百分号(%25)的字符串会出现”多次解码”陷阱。

const a = encodeURIComponent('100%');    // '100%25'
decodeURIComponent(a);                    // '100%'  正确
decodeURIComponent(decodeURIComponent(a)); // '100'  ← 第二次解码失败但 JS 抛出

后端接收时的注意

  • Node.js / Express:req.query 自动解码一次,不要再手动 decodeURIComponent
  • Spring Boot:@RequestParam 自动解码,默认 UTF-8
  • 老 Java(Tomcat 8 以前):默认 ISO-8859-1,中文要么改 URIEncoding="UTF-8",要么前端双重编码
  • PHP:$_GET 已解码

两端都解码会变成 %25% → 原文——多了一次就丢了百分号。

排错清单

参数收到是乱码或丢失时,按顺序查:

  1. 前端用的是 encodeURIComponent 还是 encodeURI?参数 value 必须用前者
  2. 后端字符集是不是 UTF-8?Tomcat / IIS 老配置可能不是
  3. 中间有没有 Nginx / CDN 做了二次解码?$arg_ 在 Nginx 里会解一次
  4. + 的值是否被当成空格?路径里 + 是字面 +,query 里是空格
  5. # 后面的内容永远不会发到服务端(fragment)

复制到工具里看

把 URL 或参数贴进工具,能实时对比 encodeURI / encodeURIComponent 两种编码结果、解码时高亮非法字符、支持一次多行批处理——改 URL 不再靠猜。

❓ 常见问题

空格到底应该编码成 + 还是 %20?

分上下文。URL 路径application/json body 必须用 %20(RFC 3986);application/x-www-form-urlencoded 的表单 body 和 query string 的表单序列化+(HTML 规范)。现代 API 绝大多数走 JSON body 或标准 URL,一律 %20 最保险。encodeURIComponent 编码的是 %20

escape() 还能用吗?

不要用。escape() 是 1995 年遗留 API,JavaScript 规范已经 deprecated:它对中文使用 %uXXXX 非标准格式(大部分服务器不识别),对 ASCII 又漏了 + / @ 等字符。新代码一律 encodeURIComponent,存量代码也建议替换。

为什么拼 URL 时要对整个 URL 用 encodeURI,对参数用 encodeURIComponent?

encodeURI 把"合法 URL 结构字符"(: / ? & = # @ 等)保留不编码——适合编码整个 URL防止意外字符。encodeURIComponent 把这些也编码——因为作为 query 参数 value 时,这些字符是分隔符,必须转义才能穿越。规则:结构字符用 encodeURI,value 用 encodeURIComponent。

中文参数后端收到是乱码怎么办?

99% 是编码不一致。现代标准一律 UTF-8 → encodeURIComponent"张三" → %E5%BC%A0%E4%B8%89。如果后端是老 Java/PHP 默认 GBK 解码,会变乱码。要么后端改 UTF-8(正确做法),要么前端先 unescape + iconv 转 GBK(兼容老系统)——现代项目不建议走后者。

🔗 打开 URL 编解码 encodeURIComponent / encodeURI · 实时 · 互换 · 错误高亮

📖 同一工具的其他教程