如何使用 URL 编码与解码工具
- 选择编码或解码。
- 选择一种模式:组件用于单个查询值或路径段,完整 URL 则保持 URL 的结构(
:、/、?、&)不变。 - 粘贴文本或 URL,并复制结果。
一切都在浏览器中处理。URL 的查询字符串中常常带有令牌和个人数据,这些内容都不会被上传或存储。
什么是百分号编码?
URL 只能包含有限的一组 ASCII 字符。RFC 3986 定义的百分号编码,把任何其他字节表示为一个百分号后跟两位十六进制数字。文本先被转换为 UTF-8 字节,然后每个需要转义的字节写成 %XX:
café & crème → caf%C3%A9%20%26%20cr%C3%A8me
这里 é 是两个 UTF-8 字节(C3 A9),空格变成 %20,和号变成 %26。
保留字符与非保留字符
| 分组 | 字符 | 含义 |
|---|---|---|
| 非保留字符 | A–Z a–z 0–9 - . _ ~ | 从不需要编码。 |
| 保留字符:gen-delims | : / ? # [ ] @ | 分隔 URL 的主要部分。 |
| 保留字符:sub-delims | ! $ & ' ( ) * + , ; = | 分隔某一部分内的数据,例如查询字符串中的 & 和 =。 |
当保留字符作为数据而不是分隔符出现时,必须对其编码。搜索 R&D 时必须发送为 q=R%26D;否则服务器会看到名为 D 的第二个参数。
encodeURIComponent 与 encodeURI
JavaScript 提供了两个函数,选错其中一个是导致缺陷的常见原因:
encodeURIComponent()会对除A–Z a–z 0–9 - _ . ! ~ * ' ( )之外的所有字符编码。把它用于单个值:查询参数、路径段、片段数据。encodeURI()还会保留; , / ? : @ & = + $ #不变,因此可以应用于完整的 URL而不破坏其结构。它无法保护包含&或#的值。
encodeURI("https://example.com/a b?q=R&D")
// "https://example.com/a%20b?q=R&D" (& left alone)
"https://example.com/search?q=" + encodeURIComponent("R&D")
// "https://example.com/search?q=R%26D"
更好的办法是让 URLSearchParams 或所用编程语言的 URL 库来构建查询字符串。
常见陷阱
+ 与 %20
以 application/x-www-form-urlencoded 提交的 HTML 表单会把空格编码为 +。而在 RFC 3986 的 URL 中,+ 是字面的加号,空格是 %20。不知道使用了哪种约定的解码器,可能会把 C++ 变成 C ,或者把本该是空格的位置留下 +。为稳妥起见,请把真正的加号编码为 %2B。
Python: urllib.parse.quote("a b&c") → a%20b%26c
urllib.parse.quote_plus("a b&c") → a+b%26c
重复编码
对已编码的字符串再次编码,会转义百分号本身:%20 变成 %2520。这通常发生在某个值先被您的代码编码、又被框架或 HTTP 客户端再编码一次的时候。如果在 URL 中看到 %25,就要怀疑是重复编码。解码两次同样有害:它可能把用户数据中字面的 %41 变成 A。
把整个 URL 当作组件来编码
对完整 URL 运行 encodeURIComponent 会转义 :// 和每一个 /,得到 https%3A%2F%2F...。只有当该 URL 本身是某个参数的值(例如 redirect_uri)时,这样做才是正确的。
小提示
- 百分号编码中的十六进制数字不区分大小写,但 RFC 3986 推荐使用大写(
%2F,而不是%2f)。 - 国际化域名不使用百分号编码;它们改用 Punycode(
xn--)。 - 需要在 URL 中传输二进制数据?URL 安全的 Base64 比对每个字节做百分号编码更紧凑。
- 用 HTTP响应头检测查看服务器如何处理您编码后的请求。
常见问题
为什么空格有时是 +,有时是 %20?
+ 来自查询字符串和 POST 请求体中使用的 HTML 表单编码;%20 则是 RFC 3986 的通用编码,在 URL 的任何位置都有效。拿不准时,请使用 %20。
哪些字符从不需要编码?
非保留字符集:字母、数字、连字符、句点、下划线和波浪号。其他所有字符,只要是值的一部分,都应当编码。
URL 编码是一种安全措施吗?
不是。它只是让数据在 URL 内部语法上安全,并且完全可逆。它本身既不能隐藏数据,也不能防止注入。
如何解码带有 %uXXXX 序列的 URL?
%uXXXX 是已弃用的 JavaScript escape() 函数产生的非标准格式。标准解码器会拒绝它;必须另行转换。
更新于