关于 URL 编码解码工具
URL 编解码工具提供两种范围的百分号编码:「URL 组件」用于查询参数、路径段这类单个值,「完整 URI」用于分隔符必须保留的整条地址。输入框会实时校验百分号序列,格式不对的值在你点击转换之前就会被标出来。
百分号编码把一个字节写成百分号加两位十六进制,真正要回答的问题只有一个:哪些字符算数据,哪些字符算结构。在完整 URI 里,斜杠、问号、& 和 # 属于结构,必须保持原样;而在单个值内部,同样这些字符属于数据,必须转义,否则它们会悄悄改变整条 URL 的形状。非 ASCII 字符会先按 UTF-8 编码,再逐字节做百分号转义——这就是为什么一个汉字会变成九个字符的转义序列。
如何使用这个开发者工具
- 先选择「编码」或「解码」。
- 再选择范围:单个值选「URL 组件」,处理整条地址时选「完整 URI」。
- 粘贴内容并留意状态提示;解码模式下它会立即告诉你百分号序列是否合法。
- 转换后重点检查结果里的保留字符,尤其是 &、=、?、/ 和 #。
- 最终的 URL 应该由「字面分隔符 + 组件编码后的值」拼出来,而不是对拼好的整串再编码一次。
实例:一个回跳参数
一条回调 URL 需要塞进另一条 URL 的查询串里。两种范围中只有一种能产出可用的链接。
https://example.com/cb?state=a b&next=/homeURL 组件 :https%3A%2F%2Fexample.com%2Fcb%3Fstate%3Da%20b%26next%3D%2Fhome
完整 URI :https://example.com/cb?state=a%20b&next=/home只有组件形式能接在 redirect= 后面,拼出 https://sso.example.com/login?redirect=https%3A%2F%2Fexample.com%2Fcb%3Fstate%3Da%20b%26next%3D%2Fhome。完整 URI 形式保留了字面的 &,接收方服务器会把 next=/home 当成它自己登录地址上的参数,回调地址就这样丢了一半。
两种范围对各字符的处理
两种范围都会编码空格和所有非 ASCII 字节,区别只在于那些撑起 URL 结构的保留字符。
| 字符 | URL 组件 | 完整 URI | 为什么要紧 |
|---|---|---|---|
| 空格 | %20 | %20 | URL 中不允许出现未编码的空格 |
| & | %26 | & | 分隔查询参数 |
| = | %3D | = | 分隔参数名与参数值 |
| ? | %3F | ? | 开启查询串 |
| / | %2F | / | 分隔路径段 |
| # | %23 | # | 开启片段标识,而片段永远不会发给服务器 |
| + | %2B | + | 表单解码器会把它读成空格 |
| : 与 @ | %3A 与 %40 | : 与 @ | 协议与 userinfo 的分隔符 |
| % | %25 | %25 | 必须转义,否则解码失败 |
| 中 | %E4%B8%AD | %E4%B8%AD | 按 UTF-8 编码,每个汉字三字节 |
| - . _ ~ ! * ' ( ) | 保持原样 | 保持原样 | 非保留字符与子分隔符,两种范围都不动 |
常见问题排查
参数传到服务端时,从第一个 & 起就被截断了。
成因 这个值是按「完整 URI」范围编码的,或者根本没编码,于是它自带的 & 被接收方当成了分隔符。
解决办法 每个值都按「URL 组件」范围编码,再自己拼接。写代码时交给 URLSearchParams 之类的接口来构造查询串,从根上避免这个问题。
空格变成了加号,或者加号变成了空格。
成因 这里同时有两套编码在起作用。百分号编码把空格写成 %20,而 application/x-www-form-urlencoded 把它写成 +。本工具解码时绝不会把 + 转成空格,因为在路径或片段里加号就是字面字符。
解决办法 处理表单编码的数据时,先把 + 换成 %20 再解码,或者直接用遵循表单规则的 URLSearchParams 解析。
解码时提示编码格式无效。
成因 某个百分号后面不是两位十六进制数字,或者多字节 UTF-8 序列不完整。常见于日志在转义序列中间截断,或者粘进了 Windows 路径、带百分号的数字。
解决办法 看字符串里最后一个百分号:如果它后面不足两位数字,说明值被截断了。文本中本来就含百分号时,请先把它转义成 %25 再编码。
值里出现了你从没写过的 %2520 或 %25 序列。
成因 它被编码了两次,通常是应用编了一次,网关或客户端库以为拿到的是原始值又编了一次。
解决办法 先解一次看看:结果里如果还有合法转义,就说明是双重编码。去修那个「对已编码的值再编一次」的环节,而不是在下游反复补偿。
带非 ASCII 字符的路径在浏览器里正常,到服务端就不行了。
成因 地址栏显示的是解码后的形态,实际发出的是百分号编码的 UTF-8。服务端若按别的字符集解码,这些字节就会变成乱码。
解决办法 把服务端日志里的原始请求行与这里编码出来的结果比对,并把服务端的 URL 解码字符集配置成 UTF-8——所有浏览器发的都是它。
适合用这个工具的场景
- 构造需要承载一整条 URL 的回跳、回调或 state 参数。
- 读懂日志行或报错信息里那串百分号编码的 URL。
- 解释签名不一致的问题:签名方和发送方对同一个值采用了不同的编码方式。
- 修好从聊天窗口复制出来、夹着空格或换行的链接。
应该换用别的工具的场景
- 构造要求空格变加号的表单请求体,请用 URLSearchParams 或 HTTP 客户端自带的表单编码器。
- 为网页文本做转义。标记需要的是实体转义,请用 HTML 实体编解码工具。
- 判断 URL 是否可达或安全。本工具从不发起连接,可达性请交给网站检查工具。
隐私与数据处理
编解码使用浏览器自带的 URI 函数,在当前标签页内完成。工具从不访问这个地址,所以它无法告诉你链接是否可达、是否会跳转、是否安全;你粘贴的内容也不会被传输或保存。从浏览器复制的 URL 经常在查询串里带着会话标识和一次性令牌,分享之前请先抹掉。
相关开发者工具
常见问题
什么时候用组件范围,什么时候用完整 URI?
只要是单个值就用组件范围:查询参数、路径段、片段标识都算。只有当你手里已经是一条结构正确的完整地址、只想把其中的空格和非 ASCII 字符转义掉时,才用完整 URI。
为什么加号没有被解码成空格?
因为那条规则属于表单编码,不属于 URI。在路径、片段和一般查询值里,加号就是字面的加号,强行转换会破坏 Base64 载荷、电话号码之类的数据。
哪些字符永远不会被编码?
非保留字符集合,也就是字母、数字、连字符、句点、下划线和波浪号,再加上浏览器编码器不动的子分隔符 ! * ' ( )。其余字符要么两种范围都编码,要么只在组件范围编码。
汉字和 emoji 是怎么编码的?
先转成 UTF-8 字节,每个字节再写成一个百分号转义,所以一个汉字产出九个字符、一个 emoji 十二个。正因为膨胀得快,长的非 ASCII URL 很容易撞上长度上限。
百分号编码算一种安全措施吗?
不算。它保护的是结构,不做任何净化。解码后的 URL 依然可能指向恶意站点,而一个编码得当的值,在你的应用解释它之后同样可能有害。
放进链接之前要把整条 URL 编码一遍吗?
不要。对成品 URL 编码会把它自己的分隔符一并转义,直接破坏这条链接。正确做法是只编码各个值,再用字面分隔符把它们拼起来。