创见博客
encodeURIComponent 是什么?为什么需要它,又该怎么用
七崽爱吃小饼干2026/10/16阅读 0

先看一个线上事故级别的例子:

js
const keyword = "a&b=c";
const url = `/search?q=${keyword}`;
// /search?q=a&b=c

你本想搜「a&b=c」,结果后端收到的 q 是 a,还莫名其妙多了个参数 b=c。因为 & 和 = 在 URL 里是语法字符,它们一到查询串里就被解析成了参数分隔符和赋值符——你的值被拆碎了。

修法只有一步:

js
const url = `/search?q=${encodeURIComponent(keyword)}`;
// /search?q=a%26b%3Dc

encodeURIComponent 就是干这个的。这篇讲清它是什么、为什么需要、怎么用。

一、它是什么

encodeURIComponent() 是 JS 的全局函数,作用是把一个字符串编码成合法的 URI 组件。

它的规则很简单:把除下面这些字符之外的所有字符,按 UTF-8 字节转成 %XX 形式:

A-Z a-z 0-9 - _ . ! ~ * ' ( )

这个「不编码白名单」只有 9 个符号加字母数字。其余全部转义,包括 & = ? / # 空格 + : @ 等等。

js
encodeURIComponent("a b&c=中");
// "a%20b%26c%3D%E4%B8%AD"

逐个看:

原字符编码后原因
空格%20空格在 URL 里不合法
&%26会被当成参数分隔符
=%3D会被当成键值分隔符
中%E4%B8%AD非 ASCII,按 UTF-8 三字节编码

配套的解码函数是 decodeURIComponent(),把 %XX 还原回原字符:

js
decodeURIComponent("a%20b%26c%3D%E4%B8%AD");
// "a b&c=中"

二、为什么需要它

1. URL 有「保留字符」,它们不能随便出现在值里

URL 是有语法的,某些字符被占用了固定含义:

字符在 URL 里的含义
?查询串开始
&参数分隔
=键值分隔
#片段(hash)开始
/路径分隔
+在 query 里常被解释为空格

如果你把用户的原始输入直接塞进 URL,这些字符就会被当成语法解析,值被破坏、参数串位、甚至跳到错误的 hash。

编码的本质,就是把「数据」和「语法」区分开:让值里的特殊字符不再有语法意义,老老实实当一个普通字节。%26 对 URL 解析器来说就是普通字符「&」,不会触发分隔。

2. 非 ASCII 和非法字符必须转义

中文、emoji、空格这些字符,在 URL 规范里本来就不允许直接出现(或者行为不确定)。编码把它们转成纯 ASCII 的 %XX 序列,保证 URL 在任何环境下都能正确传输、不被截断或乱码。

js
encodeURIComponent("你好 world");
// "%E4%BD%A0%E5%A5%BD%20world"

三、怎么用

场景一:拼接查询参数(最常用)

js
const params = { q: "a&b", page: 1, tag: "前端 教程" };

const query = Object.entries(params)
  .map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`)
  .join("&");

const url = `/search?${query}`;
// "/search?q=a%26b&page=1&tag=%E5%89%8D%E7%AB%AF%20%E6%95%99%E7%A8%8B"

键和值都要编码,因为键里同样可能出现特殊字符。如果查询参数较多,直接用 URLSearchParams 更省心——它会自动帮你编码:

js
const params = new URLSearchParams({ q: "a&b", tag: "前端 教程" });
`/search?${params}`;
// "/search?q=a%26b&tag=%E5%89%8D%E7%AB%AF+%E6%95%99%E7%A8%8B"

注意一个细节差异:URLSearchParams 把空格编码成 +,而 encodeURIComponent 编成 %20。两者在 query 里通常都能被正确解析,但 + 只在 query 语义下等于空格,放到路径里就是字面的加号。

场景二:构造路径段

动态拼进路径的部分也要编码,否则 / 会截断路径:

js
const slug = "vue/router";
const url = `/docs/${encodeURIComponent(slug)}`;
// "/docs/vue%2Frouter" —— %2F 是字面的斜杠,不会变成路径分隔

场景三:拼接完整的跳转地址作为参数

把「一个完整 URL」当作另一个 URL 的参数时,必须整体编码:

js
const target = "https://example.com/a?x=1&y=2";
const loginUrl = `/login?redirect=${encodeURIComponent(target)}`;
// "/login?redirect=https%3A%2F%2Fexample.com%2Fa%3Fx%3D1%26y%3D2"

这样目标地址里的 ? & = / 都不会破坏外层 URL 的结构。

四、别用混:encodeURI 和 escape

浏览器有三个长得像的函数,用途完全不同:

函数不编码的字符用途
encodeURI保留 :/?#[]@!$&'()*+,;= 等结构字符编码一整个 URL
encodeURIComponent只保留 A-Za-z0-9-_.!~*'()编码 URL 里的某一段/某个值
escape(已废弃)——不要用,逻辑和 URL 无关

关键差异在那几个结构字符:

js
encodeURI("https://a.com/x y?q=中&n=1");
// "https://a.com/x%20y?q=%E4%B8%AD&n=1"
//  ↑ : / ? & = 都保留 —— 因为它编的是「完整 URL」,不能动结构

encodeURIComponent("https://a.com/x?q=中&n=1");
// "https%3A%2F%2Fa.com%2Fx%3Fq%3D%E4%B8%AD%26n%3D1"
//  ↑ 结构字符全被编码 —— 因为它把整串当成「一个值」

所以:

  • 拼参数、拼路径段 → 一律 encodeURIComponent;
  • 只给用户输入的空格/中文做「整条 URL 的消毒」→ 才用 encodeURI;
  • 实践中拼参数用 encodeURIComponent 或 URLSearchParams,几乎不用 encodeURI。

最典型的错误是拿 encodeURI 去编码参数值——它不编 & 和 =,照样把参数拆碎:

js
`/search?q=${encodeURI("a&b=c")}`;
// "/search?q=a&b=c" —— 没修好!
`/search?q=${encodeURIComponent("a&b=c")}`;
// "/search?q=a%26b%3Dc" —— 这才是对的

五、几个常见的坑

1. 双重编码。 已经编码过的字符串再编一次,% 会被编成 %25:

js
const once = encodeURIComponent("a b");   // "a%20b"
encodeURIComponent(once);                  // "a%2520b" —— 编过头了
// 而后端 decodeURIComponent 一次只能还原成 "a%20b",还原不回去

排查这类问题就问一句:这个值之前是否已经编码过? 编码只应发生在「原始数据 → URL」这一次。

2. decodeURIComponent 会抛错。 遇到不完整的 % 序列会抛 URIError:

js
decodeURIComponent("%E4"); // URIError: URI malformed

拿用户可控的字符串解码时要兜底:

js
function safeDecode(str) {
  try {
    return decodeURIComponent(str);
  } catch {
    return str;
  }
}

3. 它不编码 !'()*。 这几个符号在白名单里,严格场景(如某些签名、OAuth)若要求它们也转义,需要手动替换。这也是 encodeURIComponent 和 URLSearchParams 输出不完全一致的原因之一。

4. 空格:%20 还是 +? encodeURIComponent 给 %20,URLSearchParams 给 +。在查询串里 + 等价于空格;但在路径里 + 是字面的加号,不会被解码成空格。跨层传递时留意这一层差异。

六、小结

是什么:encodeURIComponent(str) 把字符串编成合法 URI 组件——除 A-Za-z0-9-_.!~*'() 外全部转成 %XX,配套解码是 decodeURIComponent。

为什么:URL 有语法,? & = # / 等是保留字符。不编码就会被当成语法解析,导致值被破坏、参数错位。编码让「数据」不再有语法含义。

怎么用:

场景写法
拼查询参数encodeURIComponent(key) + "=" + encodeURIComponent(value) 或 URLSearchParams
拼路径段encodeURIComponent(segment)
把完整 URL 当参数encodeURIComponent(fullUrl)
整条 URL 消毒才用 encodeURI(实践很少)

一句话:只要是把「值」拼进 URL,就用 encodeURIComponent;整串 URL 不要编,用 encodeURI。

评论
0/100