URL 编码完全指南:为什么中文链接会变成 %E4%B8%AD

最后更新:2026-09-14

URL 的语法只允许一小部分 ASCII 字符原样出现,其余字符都必须转义,转义方式是把该字符的字节写成 %XX 形式,因此 URL 编码也叫百分号编码。这解释了中文链接的形态:汉字「中」在 UTF-8 下是三个字节,逐个转义后就成了 %E4%B8%AD。

理解了「先定字节、再转义字节」这条主线,绝大多数 URL 编码问题都能自己推理出来。

一、哪些字符必须编码

  • 保留字符:? # & = / : ; + @ $ , 等在 URL 中有语法作用,作为数据出现时必须编码;
  • 不安全字符:空格、引号、尖括号、反引号、花括号,以及控制字符;
  • 非 ASCII 字符:中文、日文、emoji 等,必须先按 UTF-8 取字节再逐字节转义(现代规范统一使用 UTF-8,不再使用 GBK);
  • 无需编码:字母、数字与 - _ . ~ 这四类未保留标点。

二、最实用的一节:两个函数的区别

JavaScript 里有两个容易混用的函数,选错是「链接打不开」类故障的头号原因:

  • encodeURIComponent:会编码 / ? : # & = + 等所有保留字符。它应该用于参数值——因为参数值里的 & 只是普通字符,必须编码,否则会被当成参数分隔符,把 URL 结构撕开;
  • encodeURI:保留 / ? : # & = + 等结构字符不编码,只处理空格与中文。它应该用于整条 URL,例如把用户输入的完整地址规范化。

三、反例:一个典型的错误用法

假设要把关键词「a&b」拼进搜索地址。若用 encodeURI,得到 ?q=a&b,服务端会解析出 q=a 与一个名为 b 的空参数——用户搜的内容被悄悄改掉了。正确做法是用 encodeURIComponent,得到 ?q=a%26b。

反过来,如果对整条 URL 使用 encodeURIComponent,会把协议与路径里的 : 与 / 一并转义,链接直接失效。这就是「参数值用 component、整条 URL 用 encodeURI」这条经验规则的由来。

四、空格该用 %20 还是加号

两种写法都存在,但语义不同。%20 是「空格这个字符的转义」,在任何位置都表示空格;加号是 application/x-www-form-urlencoded 表单编码的历史约定,只在查询串与表单体里表示空格。

因此结论是:路径(path)里必须用 %20,用加号会被当成字面量加号;查询串里 %20 一定正确,加号是否被还原成空格取决于服务端是否按表单规则解析。要写「加号本身」,必须编码成 %2B,否则会被还原为空格。

五、双重编码与签名失效

双重编码指同一段内容被编码两次,例如 %25(也就是百分号本身)再编一次变成 %2525。服务端只解一次,最终拿到的是没解干净的字符串,表现为「参数值正确但内容多了一串百分号」。

更隐蔽的后果出现在签名场景:如果签名计算基于原始参数,而网关又对 URL 做了一次规范化或解码重编码,签名字符串就会与服务端重算的结果不一致,报「签名错误」但参数看起来完全正确。排查时应先把 URL 完整打印出来逐层解码,比对每一层结果。

六、排查清单

  • 链接触发 404 或参数丢失 → 先确认参数值是否用了 encodeURIComponent;
  • 链接整体打不开、路径被转义 → 检查是否误用了 encodeURIComponent 处理整条 URL;
  • 中文变成乱码字符 → 检查编码侧是否使用 UTF-8 取字节;
  • 参数值里多出百分号 → 检查是否发生了双重编码;
  • 签名校验失败但参数看似一致 → 检查是否有中间层对 URL 做了二次编码或解码。

七、工具与延伸

即时验证可用 URL 编码解码工具,它同时提供 encodeURIComponent 与 encodeURI 两种模式以便对照。若乱码来自字符集而非百分比编码本身,请阅读《字符编码与乱码排查》;二进制内容的文本化则见《Base64 编码完全指南》。