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 把任意二进制数据编码为文本,会显著改变原文,用于传输二进制。