URL 编码解码完全指南:百分号编码原理
URL 编码(也称"百分号编码",Percent-Encoding)是 Web 开发中最基础却最容易出错的知识之一。无论是构建 API 请求、处理表单提交,还是调试网络请求,理解 URL 编码都至关重要。
为什么需要 URL 编码?
URL(统一资源定位符)的规范(RFC 3986)规定,URL 中只能包含特定的 ASCII 字符。当 URL 中需要包含中文、空格、特殊符号等非法字符时,必须通过百分号编码将其转换为合法格式。
// 未编码的 URL(包含中文和空格,是无效的)
https://example.com/search?q=你好 世界&lang=中文
// 编码后的合法 URL
https://example.com/search?q=%E4%BD%A0%E5%A5%BD%20%E4%B8%96%E7%95%8C&lang=%E4%B8%AD%E6%96%87
百分号编码规则
百分号编码的过程是:将字符转换为 UTF-8 字节序列,每个字节表示为 % 加两位十六进制数。
字符 UTF-8 字节 编码结果
空格 0x20 %20
! 0x21 %21
# 0x23 %23
你 0xE4BDA0 %E4%BD%A0
好 0xE5A5BD %E5%A5%BD
不需要编码的字符
以下字符在 URL 中可以直接使用,无需编码:
- 非保留字符:
A-Za-z0-9-_.~
保留字符
保留字符在 URL 中有特殊含义,作为数据使用时必须编码:
| 字符 | URL 中的含义 | 编码 |
|---|---|---|
: | 协议分隔符 | %3A |
/ | 路径分隔符 | %2F |
? | 查询字符串开始 | %3F |
# | Fragment 开始 | %23 |
& | 参数分隔符 | %26 |
= | 键值分隔符 | %3D |
+ | 空格(表单编码) | %2B |
@ | 用户信息分隔 | %40 |
JavaScript 编码函数对比
JavaScript 提供了多个 URL 编码函数,它们的行为有重要区别:
encodeURIComponent(推荐用于参数值)
编码除了 A-Z a-z 0-9 - _ . ! ~ * ' ( ) 之外的所有字符。适合编码查询参数的键或值。
encodeURIComponent("name=张三&age=25")
// "name%3D%E5%BC%A0%E4%B8%89%26age%3D25"
// 正确用法:编码参数值
const url = `https://api.example.com/search?q=${encodeURIComponent("你好 世界")}`;
// "https://api.example.com/search?q=%E4%BD%A0%E5%A5%BD%20%E4%B8%96%E7%95%8C"
encodeURI(用于完整 URL)
不编码 URL 的结构字符(: / ? # [ ] @ ! $ & ' ( ) * + , ; =)。适合编码完整 URL。
encodeURI("https://example.com/路径?q=你好")
// "https://example.com/%E8%B7%AF%E5%BE%84?q=%E4%BD%A0%E5%A5%BD"
// 注意:? 和 = 没有被编码,保留了 URL 结构
⚠️ 常见错误:用
encodeURI 编码参数值会导致 & 和 = 不被编码,破坏查询字符串结构。参数值始终用 encodeURIComponent。
函数对比速查表
| 输入 | encodeURIComponent | encodeURI |
|---|---|---|
hello world | hello%20world | hello%20world |
a=1&b=2 | a%3D1%26b%3D2 | a=1&b=2 |
你好 | %E4%BD%A0%E5%A5%BD | %E4%BD%A0%E5%A5%BD |
/path?q=1 | %2Fpath%3Fq%3D1 | /path?q=1 |
表单编码(application/x-www-form-urlencoded)
HTML 表单提交使用的编码方式与标准百分号编码略有不同:
- 空格编码为
+而非%20 - 键值对用
&连接
// URLSearchParams 自动处理表单编码
const params = new URLSearchParams();
params.append("name", "张 三");
params.append("city", "北京");
console.log(params.toString());
// "name=%E5%BC%A0+%E4%B8%89&city=%E5%8C%97%E4%BA%AC"
// 注意空格变成了 + 号
其他语言的 URL 编码
Python
from urllib.parse import quote, unquote, urlencode
# 编码单个值
quote("你好 世界")
# '%E4%BD%A0%E5%A5%BD%20%E4%B8%96%E7%95%8C'
# 编码查询参数
urlencode({"name": "张三", "age": "25"})
# 'name=%E5%BC%A0%E4%B8%89&age=25'
# 解码
unquote("%E4%BD%A0%E5%A5%BD")
# '你好'
Java
// Java 11+
import java.net.URLEncoder;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
String encoded = URLEncoder.encode("你好 世界", StandardCharsets.UTF_8);
// "%E4%BD%A0%E5%A5%BD+%E4%B8%96%E7%95%8C" (注意空格是+)
String decoded = URLDecoder.decode(encoded, StandardCharsets.UTF_8);
// "你好 世界"
💡 调试技巧:遇到 URL 编码问题时,打开浏览器开发者工具的 Network 面板,查看请求的 URL 和参数。大多数工具会自动显示解码后的参数,方便调试。
常见问题
双重编码
对已经编码的字符串再次编码,会导致 % 被编码为 %25:
encodeURIComponent("%E4%BD%A0")
// "%25E4%25BD%25A0" ← 双重编码,导致乱码!
空格的表示
空格在 URL 中有两种表示:%20(路径中)和 +(表单查询参数中)。使用 encodeURIComponent 会产生 %20,使用 URLSearchParams 会产生 +。
🛠️ 在线 URL 编码解码工具
打开 URL 工具 →延伸阅读
- Base64 编解码详解 — URL 安全 Base64 编码
- JSON 格式化指南 — API 请求中的 URL 编码参数
- 正则表达式教程 — 匹配和验证 URL 格式