米格速压
URL 编码 接口 前端

URL 编码为啥不能省?接口联调把 + 号变空格的真实事故

中文参数传过去后端收到乱码、+ 号变成空格、& 把参数截断 —— URL 编码没做对的经典事故。讲清楚 URL 为什么要编码、encodeURI 和 encodeURIComponent 的区别、什么字符必须编码。

米格速压
2026-05-157 分钟
分享

联调一个搜索接口,前端搜"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 编码问题

接口联调遇到参数乱码 / 丢失,排查:

  1. 把参数值粘到 URL 编解码工具,看编码后是什么
  2. 对比前端发出的后端收到的,看哪一步出问题
  3. 检查是不是没编码(中文 / 特殊字符直接拼)
  4. 检查是不是重复编码(出现 %25 开头的)
  5. 检查是不是 + 号变空格(用了错误的编码方式)

总结

URL 编码的核心:URL 只能用安全字符,特殊字符要转成 %XX 否则破坏结构。 记住 encodeURIComponent(编码参数值用它),避开 + 号变空格和重复编码两个坑, 接口联调就不会再为乱码扯皮。

站里的URL 编解码工具 支持双向编解码 + encodeURI / encodeURIComponent 两种模式,联调时把参数贴进去一看就知道哪一步出问题。 如果参数值是 Base64 数据,先看Base64 是什么

常见疑问

URL 为什么要编码?
URL 只能包含特定的安全字符(字母、数字和少数符号)。中文、空格、& = ? # 等字符在 URL 里要么不允许,要么有特殊含义(& 分隔参数、# 标记锚点、? 开始查询串)。如果你的参数值里有这些字符,不编码就会破坏 URL 结构。URL 编码(百分号编码)把这些字符转成 %XX 形式,让它们"安全地"出现在 URL 里。
encodeURI 和 encodeURIComponent 有什么区别?
encodeURI 用于编码整个 URL,它保留 URL 结构字符(: / ? # & = 等不编码),适合编码一个完整的网址。encodeURIComponent 用于编码单个参数值,它把 : / ? # & = 也编码,适合做查询参数的值。规则:编码整个 URL 用 encodeURI,编码单个参数值用 encodeURIComponent(99% 的场景用后者)。
为什么 + 号传到后端变成空格了?
这是 URL 编码历史遗留的坑。在 application/x-www-form-urlencoded 规范里,+ 号代表空格。所以你 URL 里的 + 号,后端按这个规范解码时会变成空格。如果你要传真正的 + 号(比如 "1+1=2"),必须编码成 %2B。这是接口联调最常见的事故之一。
中文参数不编码会怎样?
看情况:① 现代浏览器地址栏会自动帮你编码(你看到中文,实际发出去是编码的);② 但你在代码里手动拼 URL 字符串发请求时,不编码可能导致后端收到乱码,或者请求直接失败。所以代码里拼接带中文的 URL,一定要对中文参数做 encodeURIComponent。
已经编码过的 URL 再编码一次会怎样?
会"双重编码",出问题。比如空格 → %20(编码一次),%20 → %2520(再编码一次,% 被编码成 %25)。后端解码一次得到 %20 而不是空格,数据就错了。所以要避免重复编码:确认 URL 当前是"原文"还是"已编码",只编码一次。
哪些字符需要编码,哪些不用?
不用编码的"安全字符":字母 A-Z a-z、数字 0-9、以及 - _ . ~ 这四个符号。其他所有字符(中文、空格、& = / ? # + 等)在做参数值时都建议编码。简单记:除了字母数字和 - _ . ~,其他都编码最保险(这正是 encodeURIComponent 的行为)。
为什么有的网站 URL 里有中文能正常显示?
现代浏览器为了美观,会把 URL 里已编码的中文"解码显示"给你看(地址栏显示中文),但实际发送给服务器时还是编码的。所以你看到的"中文 URL"和实际传输的"编码 URL"是两回事。复制这种 URL 时,粘贴出来可能是编码后的 %XX 形式,这是正常的。
URL 编码和 Base64 是一回事吗?
不是。① URL 编码(百分号编码):把不安全字符转成 %XX,主要用于 URL;② Base64:把二进制转成纯文本字符,主要用于传输二进制数据。两者目的不同。有时会组合用:比如先把数据 Base64 编码,但 Base64 里的 + / = 在 URL 里有特殊含义,所以还要再 URL 编码一次(或者用 URL-safe Base64)。

看完即用

URL 编解码

中文参数 / 特殊字符 URL 编码 ↔ 解码,自动识别方向

立即免费使用
作者
米格速压

米格速压编辑组,专注于办公文件处理场景的教程编写。每周二、五更新。