为什么要编码
URL 只允许有限的字符集。中文、空格、&、=、? 这类字符必须转成 %XX 才能安全传输,否则会被解析器误认成结构分隔符。
%20 和 + 的区别
在查询串(application/x-www-form-urlencoded)里,空格历史上用 + 表示;但 URL 路径里空格只能是 %20。不同解码器对 + 的处理不一致,这正是“空格变加号”这类 bug 的来源。参数值里的空格,建议统一用 %20。
encodeURI 与 encodeURIComponent
- encodeURI:保留 URL 结构字符(
: / ? # [ ] @等),适合编码完整 URL; - encodeURIComponent:编码更彻底,适合编码单个参数值。
对完整 URL 用 encodeURIComponent 会把 :/ 也编码掉,URL 反而失效,这是最常见的误用。
中文乱码的两大根源
- 编解码不对称:编码两次却只解码一次(或反过来),结果残留 %XX;
- 字符集不一致:发送端按 UTF-8、服务端按 GBK,中文必然乱码。
常用字符编码对照
| 原字符 | 编码结果 | 说明 |
|---|---|---|
| 空格 | %20 或 + | 查询串历史上用 +,路径必须用 %20 |
| 中文“中” | %E4%B8%AD | UTF-8 的 3 个字节,各转成一个 %XX |
| & | %26 | 不编码会被当作参数分隔符 |
| = | %3D | 出现在参数值里必须转义 |
| # | %23 | 不编码会被截断成锚点 |
代码示例
// 前端:拼参数一律用 encodeURIComponent
const url = '/search?q=' + encodeURIComponent('中文 & 符号');
// => /search?q=%E4%B8%AD%E6%96%87%20%26%20%E7%AC%A6%E5%8F%B7
// Node:new URLSearchParams({ q: '中文 & 符号' }).toString()
// Python:urllib.parse.quote('中文 & 符号', safe='')
三个排查建议
- 拿不准时先解码一次,确认是不是被编码了两遍;
- 服务端收到
+时,先确认框架是否按表单规则把它当成空格,在 URL 路径里它就是字面加号; - 中文乱码优先检查两端字符集是不是都 UTF-8,而不是反复编解码。
几个常被问到的问题
路径里能用 + 表示空格吗?不能,只有查询串才可能把 + 当空格,路径里 + 就是加号。encodeURIComponent 能编码整条 URL 吗?不建议,它会把 :/?&= 一起编码,破坏结构。为什么“中”编码后是 3 组 %XX?因为 UTF-8 用 3 个字节表示它,逐字节编码就是 %E4%B8%AD。浏览器地址栏里的中文会自动编码吗?显示不编码,实际发送时仍会转成 %XX,所以手动拼 URL 务必自己编码。
动手试试:URL 编解码、Base64 编解码