URL 编码对照表
URL 百分号编码(Percent-Encoding)对照表:保留字符与其 %XX 编码一一对应,附说明,方便在拼接查询参数与路径时快速查阅。
实践注解
- encodeURI 与 encodeURIComponent 的分工不能混encodeURI 保留 : / ? # & = 等结构字符,用来编码「一整条 URL」;encodeURIComponent 会把它们全部转义,用来编码「一个参数值」。把整条 URL 交给 encodeURIComponent,会把 https:// 变成 https%3A%2F%2F 而失效。
- 空格在 query 里是 +,在路径里是 %20application/x-www-form-urlencoded 把空格编码为 +,而 URI 路径中 + 是字面加号。解析时若不做区分,搜索「a+b」与「a b」会得到同一个结果。收到的参数要先判断来源再决定 + 是否还原成空格。
- 中文优先用 UTF-8 百分号编码,别用 GBK同一串中文在 UTF-8 与 GBK 下编码出的百分号序列完全不同(例如「中」是 %E4%B8%AD 而非 %D6%D0)。跨系统传参时双方必须约定 UTF-8,否则服务端会解出乱码。
数据来源
- RFC 3986 (URI generic syntax)
- WHATWG URL Standard
- RFC 1866 (application/x-www-form-urlencoded)
上述编号、名称与定义均来自公开规范,本站不主张对规范数据本身的独创性;本页的编排方式、中文释义与实践注解由本站撰写。
原理解析
百分号编码(Percent-Encoding)是 RFC 3986 规定的 URL 安全字符表示法。URL 只允许一小部分「未保留」字符(字母、数字以及 - _ . ~)直接出现;其余字符——保留字符在非分隔用途下、空格、以及所有非 ASCII 字符——都必须转义,避免被解析器误读为结构符号。
编码规则:把字符按 UTF-8 拆成字节,每个字节写成 %XX(XX 为两位大写十六进制)。例如中文「中」的 UTF-8 是 E4 B8 AD,编码为 %E4%B8%AD。保留字符(如 ? # / & =)只有在「不是用来分隔」时才编码——这正是为什么 ? 在查询里是分隔符、但出现在参数值里要写成 %3F。
什么时候该查这张表
这张表在你要判断「某个字符该不该编码成 %XX」时有用。它的核心问题很简单:URL 里有两类字符——可以直接出现在路径里的,和必须编码的。这张表给出常用字符的编码结果与用途说明。
不该查的情况:你在做整段文本的批量编码,或需要处理非 ASCII(中文、日文、emoji)。本表覆盖的是 ASCII 范围内的常用符号;中文等多字节字符的编码是「UTF-8 字节逐个转成 %XX」,规则不同但机制一致。
判断标准:看字符在 URL 中的位置。查询串里 &、=、+ 有语义(分隔参数、键值、空格),路径里 /、:、@ 有结构意义,片段里 # 之后全是片段。这些位置上的字符必须编码,不能直接写。
特别注意空格:它在查询串中可以写成 +,在路径里必须写成 %20。这是最容易出错的一处 —— 用 + 表示空格在 URL 路径中不合法,服务器会把它当成字面的加号。
边界与常见陷阱
空格在查询串与路径里写法不同
「a=b+c」 与 「a=b%20」 在「application/x-www-form-urlencoded」查询串里等价,因为该规范把 「+」 定义为空格。但路径里没有这条规则,「%20」 才是唯一正确写法。同理,表单提交(默认 enctype)会自然产生 「+」,而 REST 路径中的空格必须显式写 「%20」,否则部分服务器按字面加号处理。
重复编码(双重编码)是常见 bug 源
对已经编码过的字符串再编码一次,「%20」 会变成 「%2520」(% 本身被编码为 %25)。典型触发场景:前端先 encodeURIComponent 再由后端或网关再编码一次;或把已编码的 URL 当作「原始 URL」传入。判断方法:合法编码结果里不会包含 「%25」,一旦看到就是多编码了。修复方式是明确约定「在哪一层完成编码」,其余层只做透传。
有些字符编码后浏览器会自动解码,调试时易误判
现代浏览器地址栏对 「%2F」(斜杠)、「%3A」(冒号)等会做规范化处理,你在 Network 面板看到的是解码后的值,而在服务端日志里看到的可能是原始值,两边对不上会让人以为编码错了。调试编码问题时要以原始 URL(Request URL 而非显示的 URL)为准,并确认服务端框架有没有做自动 URL 解码。
与相邻内容的分工
要查字符本身长什么样、码点是多少,用站内「ASCII 码」页;本页关注的是 URL 语境下的百分号编码。
要处理完整的编解码工作(含 base64、query string 解析、form 序列化),用站内 URL 相关工具;本表只给字符级对照。
要查中文等非 ASCII 字符的编码原理(为什么是三个 %XX),属于「字符编码」页的范畴,本页只覆盖 ASCII 符号。
若目的是排查某个具体链接跳转异常,需要的往往是完整的 request/response 追踪,而不是单字符编码表。
实战片段
要点:① 空格在查询串可用 +,在路径必须 %20(URL 路径里 + 是字面加号);② 合法编码结果不会含 %25,出现即说明多编码了一次,修复方式是约定「只有一层负责编码,其余透传」;③ 构造查询串优先用 URLSearchParams,它会自动把 & 和 = 正确编码,避免参数串位;④ 调试时地址栏显示的是浏览器规范化后的值,编码问题应以 Request URL 与服务端日志为准。
// ① 空格:查询串用 +,路径用 %20
const q = 'keyword=' + encodeURIComponent('a b') // keyword=a%20b(函数一律用 %20,更安全)
const legacyForm = 'keyword=a+b' // 仅在 form-urlencoded 语境下等价于空格
// ⚠️ 路径里绝不能用 + 表示空格:
new URL('https://x.dev/a b').pathname // /a%20b
new URL('https://x.dev/' + 'a+b').pathname // /a+b —— 服务器会当成字面加号
// ② 检测双重编码:合法编码结果不含 %25
const twice = encodeURIComponent('%20') // '%2520' ← % 被编码成 %25
console.log(twice.includes('%25')) // true ⇒ 多编码了
// ③ 只在约定的一层编码,其余透传
function buildQuery(params) {
const p = new URLSearchParams()
for (const [k, v] of Object.entries(params)) p.append(k, v) // 内部正确编码
return p.toString() // keyword=a+b
}
console.log(buildQuery({ keyword: 'a b', q: 'x&y' }))
// keyword=a+b&q=x%26y —— & 已被编码,参数不会串位
// ④ 调试时看原始 URL,不看地址栏显示值
console.log(location.href) // 浏览器可能已规范化
console.log(new URL(location.href).pathname) // 规范化后的路径
// 排编码问题:以 Network 面板的 Request URL 与服务端日志为准| 字符 | 编码 | 说明 |
|---|---|---|
| 空格 (space) | %20 | 表单中也可写作 +(application/x-www-form-urlencoded) |
| ! | %21 | 感叹号 |
| # | %23 | 片段标识符分隔符 |
| $ | %24 | 美元符号 |
| & | %26 | 查询参数分隔符 |
| ' | %27 | 单引号 |
| ( | %28 | 左括号 |
| ) | %29 | 右括号 |
| * | %2A | 星号 |
| + | %2B | 加号(表单中代表空格) |
| , | %2C | 逗号 |
| / | %2F | 路径分隔符 |
| : | %3A | 方案/主机分隔符 |
| ; | %3B | 参数分隔符 |
| = | %3D | 键值对分隔符 |
| ? | %3F | 查询起始符 |
| @ | %40 | 用户信息服务分隔符 |
| [ | %5B | 左方括号 |
| ] | %5D | 右方括号 |
| % | %25 | 百分号本身必须编码 |
| " | %22 | 双引号 |
| < | %3C | 小于号 |
| > | %3E | 大于号 |
| \ | %5C | 反斜杠 |
| ^ | %5E | 脱字符 |
| ` | %60 | 反引号 |
| { | %7B | 左花括号 |
| | | %7C | 竖线 |
| } | %7D | 右花括号 |
| ~ | %7E | 波浪号 |
常见问题
为什么空格有时是 %20,有时是 +?
在 application/x-www-form-urlencoded(表单提交)中空格编码为 +;而在 URL 路径或查询的百分号编码中,空格统一为 %20。两者语境不同,不要混用。
哪些字符必须编码?
RFC 3986 保留字符(: / ? # [ ] @ ! $ & ' ( ) * + , ; =)在非分隔符用途时必须编码;此外所有非 ASCII 字符(如中文)也必须编码。
% 后面为什么是两位十六进制?
百分号编码把字节表示为 %XX 形式。非 ASCII 字符先按 UTF-8 编码为若干字节,再逐字节转成 %XX。
URL 编码和 Base64 编码有什么区别?
URL 编码只转义不安全字符,保留可读结构,用于 URL;Base64 把任意二进制数据编码为文本,会显著改变原文,用于传输二进制。