联调一个搜索接口,前端搜"1+1 等于几",后端日志里收到的是"1 1 等于几" —— + 号变成了空格。前端同事说"我没动啊",后端同事说"我也没改啊", 两边对峙了半小时。
最后定位到:前端把搜索词直接拼进 URL 没做编码,+ 号被当成了空格 (URL 编码规范里 + 代表空格)。这是 URL 编码没做对的经典事故。 这篇讲清楚 URL 为什么要编码、两个编码函数怎么选、什么字符必须编码。
URL 为什么要编码
URL 只能包含特定的安全字符:字母、数字和少数符号。原因是 URL 里有些字符有特殊含义:
?标记查询串开始&分隔多个参数=分隔参数名和值#标记锚点/分隔路径
问题来了:如果你的参数值里本身就包含这些字符,会破坏 URL 结构。 比如搜索词是"A&B",拼进 URL 变成 ?q=A&B,后端会把它当成两个参数(q=A 和 B), 而不是一个值"A&B"。
URL 编码(百分号编码)就是解决这个:把特殊字符转成 %XX 形式 (X 是十六进制)。& 编码成 %26,空格编码成 %20, 这样它们就"安全地"出现在 URL 里,不会破坏结构。
两个编码函数:encodeURI vs encodeURIComponent
JavaScript 提供两个编码函数,新手最容易搞混:
encodeURI:编码整个 URL
保留 URL 结构字符(: / ? # & = 不编码),适合编码一个完整网址。
比如 encodeURI("https://x.com/搜索?q=你好") 只编码中文, 保留 :// ? = 这些结构字符。
encodeURIComponent:编码单个参数值
把结构字符也编码(: / ? # & = 都转成 %XX), 适合编码单个查询参数的值。
比如 encodeURIComponent("A&B") 把 & 编码成 %26, 这样这个值塞进 URL 不会破坏参数结构。
怎么选
- 编码整个 URL → encodeURI
- 编码单个参数值 → encodeURIComponent(99% 的场景用这个)
实际开发中你大多在拼参数值,所以记住 encodeURIComponent 就够用。
经典坑:+ 号变空格
就是我开头那个事故。在 application/x-www-form-urlencoded 规范里, + 号代表空格。所以:
- 你 URL 里的
+号,后端解码时变成空格 - 要传真正的
+号(如 "1+1=2"),必须编码成%2B
encodeURIComponent("1+1") 会正确把 + 编码成 %2B, 所以用对编码函数就不会有这个问题。手动拼 URL 才会踩坑。
哪些字符需要编码
不用编码的"安全字符":
- 字母 A-Z、a-z
- 数字 0-9
- 四个符号:
-_.~
其他所有字符(中文、空格、& = / ? # + 等)做参数值时都建议编码。 简单记:除了字母数字和 - _ . ~,其他都编码最保险(这正是 encodeURIComponent 的行为)。
另一个坑:重复编码
已经编码过的内容再编码一次,会出问题:
- 空格 →
%20(编码一次) %20→%2520(再编码,%被编码成%25)
后端解码一次得到 %20 而不是空格,数据就错了。 解决:确认当前 URL 是"原文"还是"已编码",只编码一次。 如果不确定,先解码看看(如果解码后变化了说明已编码过)。
为什么浏览器地址栏能显示中文
你在地址栏看到中文 URL,以为没编码?其实浏览器为了美观, 把已编码的中文"解码显示"给你看,实际发送给服务器时还是编码的。
所以"显示的 URL"和"实际传输的 URL"是两回事。复制这种 URL 粘贴出来, 可能变成 %E4%B8%AD%E6%96%87 这种编码形式,这是正常的。
调试 URL 编码问题
接口联调遇到参数乱码 / 丢失,排查:
- 把参数值粘到 URL 编解码工具,看编码后是什么
- 对比前端发出的和后端收到的,看哪一步出问题
- 检查是不是没编码(中文 / 特殊字符直接拼)
- 检查是不是重复编码(出现 %25 开头的)
- 检查是不是 + 号变空格(用了错误的编码方式)
总结
URL 编码的核心:URL 只能用安全字符,特殊字符要转成 %XX 否则破坏结构。 记住 encodeURIComponent(编码参数值用它),避开 + 号变空格和重复编码两个坑, 接口联调就不会再为乱码扯皮。
站里的URL 编解码工具 支持双向编解码 + encodeURI / encodeURIComponent 两种模式,联调时把参数贴进去一看就知道哪一步出问题。 如果参数值是 Base64 数据,先看Base64 是什么。