如何对字符串进行 URL 编码
- 在 文本或 URL 中输入或粘贴文本。输出会随输入实时更新。
- 在 编码方式 下选择模式:
- 组件(encodeURIComponent):用于单个查询参数值、表单字段或路径片段。
- 完整 URL(encodeURI):用于包含空格或非 ASCII 字符的完整 URL。
- 表单数据(空格转为 +):用于
application/x-www-form-urlencoded正文,以及按 HTML 表单方式构造的查询字符串。 - 所有字符:对所有字节(包括字母)做百分号编码,用于测试解码器。
- 字符集 保持 UTF-8 即可,除非接收方系统需要传统编码。
- 勾选 逐行处理 可以一次编码一组值,然后点击 复制输出。互换 会把结果送到解码器,检查往返转换是否一致。
输入为完整 URL 时,还会在输入输出框下方的表格中把它拆分为协议、主机、路径、每个查询参数和片段。
encodeURIComponent、encodeURI 与表单编码对比
同一个输入 a b&c=d/é?#+,三种常见方式的结果:
| 模式 | 输出 | 用途 |
|---|---|---|
组件(encodeURIComponent) | a%20b%26c%3Dd%2F%C3%A9%3F%23%2B | URL 中的单个值 |
完整 URL(encodeURI) | a%20b&c=d/%C3%A9?#+ | 结构已经正确的完整 URL |
表单数据(URLSearchParams) | a+b%26c%3Dd%2F%C3%A9%3F%23%2B | HTML 表单提交,以及许多查询字符串库 |
组件 只保留 A–Z a–z 0–9 - _ . ! ~ * ' ( ) 不转义。完整 URL 还会保留 ; / ? : @ & = + $ , #,也就是构成 URL 结构的字符,所以它无法保护包含这些字符的值。表单数据 只保留字母、数字和 - _ . *,并把空格写成 +。
经典的 bug 是用 完整 URL 编码来拼接 URL:?q=C++ & Go 会保留 + 和 &,服务器收到的是 q=C 加一个多余的参数。正确的做法是用 组件 编码这个值:?q=C%2B%2B%20%26%20Go。
空格、加号和其他麻烦字符
| 字符 | 编码后 | 为什么重要 |
|---|---|---|
| 空格 | %20 或 + | + 只在查询字符串和表单正文中表示空格 |
+ | %2B | 不编码的话,很多服务器会把它变成空格:+49 30 1234567 变成 49 30 1234567 |
& | %26 | 开始一个新的查询参数 |
= | %3D | 分隔名称和值;标准 Base64 以它结尾 |
/ | %2F | 分隔路径片段;有些服务器拒绝路径中的 %2F |
# | %23 | 开始片段,片段永远不会发送给服务器 |
% | %25 | 它本身必须编码,否则解码器会读到错误的转义 |
€ | %E2%82%AC | 3 个 UTF-8 字节,3 个转义 |
URL 中的 Base64 是 +、/ 和 = 问题的常见场景。要么把它作为组件做百分号编码,要么改用 Base64URL,它不使用这些字符。
非 UTF-8 字符集
百分号编码作用于字节,所以结果由字符集决定。é 在 UTF-8 中是 %C3%A9,在 Windows-1252 或 ISO-8859-1 中是 %E9。现代浏览器和 API 使用 UTF-8,但较老的 PHP 应用、部分支付网关和传统内网系统仍然需要 Latin-1 或 Windows-1252,日文网站有时用 Shift_JIS,一些老的中文系统则用 GBK。在 字符集 下选择对应的字符集即可。所选字符集中不存在的字符无法表示,请检查输出中是否有这类字符。
在代码中进行 URL 编码
encodeURIComponent("a b&c") // "a%20b%26c"
new URLSearchParams({ q: "C++ & Go" }).toString() // "q=C%2B%2B+%26+Go"
from urllib.parse import quote, quote_plus, urlencode
quote("/files/a b.txt") # '/files/a%20b.txt' (keeps / by default)
quote("/files/a b.txt", safe="") # '%2Ffiles%2Fa%20b.txt'
quote_plus("a b&c") # 'a+b%26c'
urlencode({"q": "C++ & Go"}) # 'q=C%2B%2B+%26+Go'
Python 的 quote 默认保留 /,除非传入 safe="",编码值时这一点经常让人意外。其他语言:PHP 的 rawurlencode 生成 %20,urlencode 生成 +;Java 的 URLEncoder.encode 是带 + 的表单编码;Go 有 url.PathEscape(%20)和 url.QueryEscape(+)。encodeURIComponent 不转义 ! ' ( ) *;如果需要严格符合 RFC 3986 的输出,事后再替换它们:
const strict = s => encodeURIComponent(s).replace(/[!'()*]/g,
c => "%" + c.charCodeAt(0).toString(16).toUpperCase());
JavaScript 方面的更多内容见 JavaScript Base64 页面。要反向还原,请使用 URL 解码器。
常见问题
什么是 URL 编码?
URL 编码,也叫百分号编码,会把 URL 中不允许出现或有特殊含义的字符,替换为 % 加该字符每个字节的两位十六进制数字。空格变成 %20,& 变成 %26,UTF-8 中的 é 变成 %C3%A9。
URL 中的空格该编码成 %20 还是 +?
%20 在任何地方都有效。+ 只在遵循表单编码约定的查询字符串和表单正文中表示空格;在路径中它就是加号本身。拿不准时,用 %20。
应该对整个 URL 做 URL 编码吗?
不应该,应该在插入每个值之前分别编码。用 组件 模式编码整个 URL,会把 :、/、? 和 & 也转义掉,URL 就坏了。完整 URL 模式会保留这些结构字符,只修复空格和非 ASCII 文本。
为什么编码后的字符串里有 %25?
%25 是编码后的百分号,说明输入已经编码过,又被编码了一次:a%20b 变成了 a%2520b。原始文本只需编码一次。
百分号编码中的十六进制用大写还是小写?
RFC 3986 认为 %2F 和 %2f 等价,并推荐使用大写。只有在需要与生成小写的系统保持一致时(比如比对签名),才勾选 小写 hex。