URL 编码是什么:中文变 %E4%BD%A0 的原因
把一个带中文的网址复制到聊天窗口,有时会变成 https://example.com/search?q=%E5%86%B0%E5%8E%9F 这样一长串;接口调试时,参数值里的 & 一出现就把后面的参数“吃掉”;老系统的链接解出来全是问号和方块。这些现象背后是同一件事:URL 编码(也叫百分号编码)。本文用具体例子讲清它的规则,并给出一套自己动手排查的步骤。
一、为什么网址里要编码
网址的格式规范(RFC 3986)规定,网址里可以原样出现的“安全字符”只有字母、数字,以及 -、.、_、~。另有一批字符有固定分工,比如 / 分隔路径,? 引出参数,& 分隔多个参数,= 连接参数名和值,# 引出页面内锚点。如果参数值里本身就含有这些字符,或者含有中文、空格,就必须先转换,否则服务器分不清哪个是内容,哪个是网址结构。
转换方法是:先把字符按某种字符集(现在基本都是 UTF-8)变成字节,再把每个字节写成“% 加两位十六进制数”。
二、一个完整的例子
以“冰原 工具箱”为例:
冰原 工具箱
→ UTF-8 字节 E5 86 B0 E5 8E 9F 20 ...
→ %E5%86%B0%E5%8E%9F%20
%E5%B7%A5%E5%85%B7%E7%AE%B1
每个常用汉字在 UTF-8 里占 3 个字节,所以一个汉字会变成 9 个字符,如“冰”是 %E5%86%B0。空格的字节是 20,写成 %20。你不需要手算,把内容粘贴到本站 URL 编码解码工具 即可得到同样的结果,也可以反过来把 %E5%86%B0%E5%8E%9F 还原成“冰原”。
三、编码“参数值”还是“整个网址”
这是最常见的出错点。浏览器和很多语言提供两类函数,以 JavaScript 为例:
encodeURIComponent:用于单个参数值。除字母、数字和- _ . ! ~ * ' ( )外全部转义,所以&、=、/、?都会被转成%26、%3D、%2F、%3F。encodeURI:用于整个网址。会保留: / ? # & =等表示网址结构的字符,只转义中文、空格等。
例如要把 a&b=c 作为参数 q 的值,正确的做法是只对值编码:?q=a%26b%3Dc。如果对整个“q=a&b=c”做 encodeURI,& 保持原样,服务器会把它理解成两个参数。反过来,对整个网址用 encodeURIComponent,连 https:// 里的冒号和斜杠都会被转义,网址就不能用了。
四、空格为什么有时是 %20,有时是 +
标准的网址写法里,空格是 %20。而浏览器提交网页表单时,使用的是另一种格式(application/x-www-form-urlencoded),习惯把空格写成 +。所以在“查询字符串”里你会看到两种写法,服务器一般都能处理;但在网址的路径部分,+ 就是一个普通加号,不要随意当作空格。做解码时如果结果里多了加号或少了空格,先想想是不是这个原因。本站工具里分别提供了“编码时空格写成 +”和“解码时 + 当作空格”两个选项。
五、四种常见故障和排查
- 出现 %25:二次编码。%25 就是百分号本身。如果链接里看到
%25E5%2586,说明已经编码过的内容又被编码了一次。解决:找到重复编码的那一步,只保留一次。用工具解码一次,看是否得到%E5%86这样的结果,就能确认。 - 解码后是乱码或报错:字符集不对。现在的网站基本使用 UTF-8,但一些老系统用 GBK。同样是“中文”,UTF-8 编码是
%E4%B8%AD%E6%96%87,GBK 编码是%D6%D0%CE%C4。解不出来时,把解码字符集切换到 GBK 再试。字符集的差异可以读 《UTF-8 和 GBK 有什么区别》。 - 提示 % 后面不是十六进制:链接被截断。聊天软件或短信可能把长链接从中间截断,导致末尾只剩
%E5%8。这种链接无法还原,需要重新获取完整地址。 - 参数丢失:值里的 & 或 # 没有转义。
#之后的内容不会发给服务器,&会切断参数。凡是用户输入或含有特殊符号的值,都要先编码再拼接。
六、动手:三步确认一个链接有没有问题
- 把可疑链接粘贴到 URL 编码解码工具,选 UTF-8 点“解码”,看结果是否可读。
- 如果解出来仍含有
%XX,说明二次编码;再解一次直到不再变化。 - 如果是乱码,切换到 GBK 再解;仍不行,多半是链接已经被截断或损坏。
如果参数是 JSON,可以先用 JSON 格式化工具 检查结构,再整体编码后放进网址;二进制内容则更常用 Base64,并使用 URL 安全格式(把 +、/ 换成 -、_)。
七、小结
记住三句话:编码对象是“值”而不是整条网址;先 UTF-8 后百分号,解码反过来;乱码先查是不是二次编码和字符集。更完整的规则以 RFC 3986 和 MDN 的 encodeURIComponent 文档 为准。
八、给开发者的几条习惯
- 拼接网址时,不要手写字符串加号,使用语言自带的参数构造方法(如 URLSearchParams),让它替你做编码。
- 接口文档里写明参数的字符集;新项目统一使用 UTF-8。
- 日志里同时记录编码前后的值,排查时可以一眼看出是哪一步出了问题。
- 不要把用户提供的网址直接拼进跳转链接,先做校验,避免被利用为恶意跳转。