反馈

URL 编码原理:百分号编码规则和常见坑

URL 里经常能看到一堆 %E4%B8%AD 这样的百分号符号,这就是 URL 编码(也叫百分号编码)。它存在的原因很直接:URL 的语法本身对能出现哪些字符有严格限制,中文、空格、某些符号都不能直接塞进去。


目录

  1. 为什么 URL 需要编码
  2. 百分号编码规则
  3. encodeURIComponent 和 encodeURI 的区别
  4. 表单编码的历史遗留:空格变成 +

1. 为什么 URL 需要编码

URL 语法里,/?&=# 等符号都有结构性含义(分隔路径、开始查询参数、分隔参数、赋值、定位锚点),如果内容本身也包含这些符号,直接放进 URL 会造成解析歧义——服务器分不清这是"数据"还是"结构符号"。另外,URL 传统上只允许一部分 ASCII 字符,中文、日文等非 ASCII 字符以及空格都不被允许直接出现。解决方法就是把这些"有问题"的字符转换成安全的 %XX 形式。

2. 百分号编码规则

规则很直接:把字符对应的字节,用两位十六进制数表示,前面加上 %。比如空格的 ASCII 码是 0x20,编码后就是 %20;中文字符要先按 UTF-8 转成字节,再逐字节编码——"中"字的 UTF-8 编码是三个字节 E4 B8 AD,所以编码结果是 %E4%B8%AD。这也是为什么中文字符编码后往往变成一长串 %XX%XX%XX——一个汉字通常占 UTF-8 的 3 个字节,编码后就是 3 组 %XX

3. encodeURIComponent 和 encodeURI 的区别

JavaScript 提供了两个编码函数,用途不同:

  • encodeURIComponent:编码范围最广,几乎所有特殊字符(包括 /?&=)都会被编码——用于编码单个参数值,因为参数值本身不应该包含 URL 结构符号,如果参数值里恰好有 &=,必须编码掉,否则会被误判成新的参数分隔符
  • encodeURI:编码范围小得多,会保留 /?&=# 这些 URL 结构字符不编码——用于编码整条 URL,因为这些符号在整条 URL 里是有意义的结构,不应该被编码掉

一个常见的坑:如果用 encodeURI 去编码一个参数值(而不是整条 URL),参数值里的 &= 不会被编码,一旦参数值本身包含这些符号,就会破坏 URL 的参数结构——所以编码单个参数值时应该用 encodeURIComponent,编码整条 URL 时才用 encodeURI

4. 表单编码的历史遗留:空格变成 +

HTML 表单提交(Content-Type: application/x-www-form-urlencoded)用的编码规则和标准 URL 百分号编码略有差异:空格被编码成 + 号,而不是 %20。这是历史遗留问题——早期 HTML 表单规范就是这么定义的,一直沿用至今。这也是为什么处理表单数据时,如果直接按标准 URL 解码规则去解析(把 + 当作字面的加号而不是空格),会得到错误的结果——必须先把 + 换成空格,再做百分号解码。


在线工具:URL编码解码 · Escape编码解码