URL 编解码
把中文、空格、emoji 这类不能直接出现在 URL 里的字符和 %XX 互相转换,并区分「编码一个参数值」和「编码整个网址」两种场景。
输入
输出
encodeURIComponent 和 encodeURI 差在哪
encodeURIComponent 会把 / ? : & = # + 这些在 URL 里有特殊含义的字符一起编码,所以它适合编码一个参数值;encodeURI 会放过这些结构字符,只把中文、空格等非法字符编码,所以它适合编码一个完整的网址。判断标准只有一个问题:你手上这段字符串是 URL 的一部分,还是整个 URL?
| 输入 | encodeURIComponent | encodeURI |
|---|---|---|
a=1&b=2 | a%3D1%26b%3D2 | a=1&b=2 |
中文 | %E4%B8%AD%E6%96%87 | %E4%B8%AD%E6%96%87 |
https://a.com/b?c=d | https%3A%2F%2Fa.com%2Fb%3Fc%3Dd | https://a.com/b?c=d |
用错方向的后果很直接:把整个网址丢进 encodeURIComponent,https:// 会变成 https%3A%2F%2F,链接直接失效;反过来用 encodeURI 编码一个参数值,值里的 & 不会转义,服务端会把它当成新的参数分隔符,参数被截成两段。
中文、空格和 emoji 编出来是什么样
编码的本质是把字符按 UTF-8 转成字节,再逐字节写成 %XX。一个常用汉字是 3 字节,所以「中」是 %E4%B8%AD;空格 1 字节,是 %20;emoji 处在基本平面之外,占 4 字节,一个 🐟 会变成 %F0%9F%90%9F。看到一长串百分号不用慌,整段粘进解码模式就能还原。
表单模式
application/x-www-form-urlencoded 里空格惯例写成 +(而不是 %20),+ 本身要写成 %2B。编解码都遵守这个约定的场合,勾上「表单模式」即可;勾选后解码会把 + 还原成空格。
四个常见的坑
- 百分号要写成
%25。原文里如果有一个裸的%,解码时会被当成百分号序列的开头,直接报错。 - 重复编码。已经编码过的字符串再编一次,
%E4%B8%AD会变成%25E4%25B8%25AD,页面上就看到「%25E4…」。这类输出多解码一次即可还原。 - 参数值里的
#要编码成%23。井号在 URL 里是锚点起点,不编码的话它后面的内容不会发给服务端。 - 解码报错不一定是工具的问题。遇到单独的
%、%ZZ或截断的%E4,decodeURIComponent一定会抛异常。这里会捕获并指出是第几行,不会给你一个 undefined。
常见问题
为什么不能用 encodeURIComponent 编码整个 URL?
它会把冒号、斜杠、问号、等号、& 全部编码,得到
https%3A%2F%2F...,这串东西已经不是可用的链接了。整个网址用 encodeURI,它专门为「保留 URL 结构」设计。链接里的中文显示成一堆百分号怎么办?
先用解码模式还原一次,能还原说明只是显示层没解码,或者服务端把编码后的字符串又编码了一遍。如果还原出来是「䏿–‡」这种拉丁字母乱码,说明是 UTF-8 被当成 Latin-1 或 Windows-1252 读了,可以用中文转义的「先修复 UTF-8 乱码」还原。
为什么解码之后 + 号还是 + 号?
百分号编解码本身不处理
+,+ 表示空格只是 HTML 表单编码的约定。确认数据来自表单或查询串时,勾上「表单模式」再解码。一次能处理多条参数值吗?
可以。「按行处理」默认开启,每一行独立编解码,行与行之间的换行不会被编成
%0A,适合把一列参数值批量转换。取消勾选则整段当成一个字符串处理。emoji 为什么编出来这么长?
emoji 的码点大于 U+FFFF,UTF-8 需要 4 个字节,所以是 8 个十六进制字符、四个
%XX。这是正常的,不是工具多编了。