把「为什么网址里要有 %20、%E4%BD%A0 这种东西」讲清楚的一页。这一页是概念讲解,不是工具。
百分号编码就是把一个「不能直接放进网址」的字节,写成 % 加上两位十六进制 的形式。 比如空格写成 %20,中文「你」写成 %E4%BD%A0。 它也常被称为 URL 编码(URL Encoding),正式名字在 RFC 3986 里叫 Percent-Encoding。
网址(URI)最初是为英文、纯 ASCII 设计的,而且里面有一批字符被赋予了结构含义。这带来三个问题:
百分号编码就是这三个问题的统一解法:凡是「不安全」或「想当内容用」的字符,一律写成 %XX。
很多人以为「每个字符对应一个 %XX」,其实中间多了一层 UTF-8 字节。
| 字符 | UTF-8 字节(十六进制) | 百分号编码结果 |
|---|---|---|
| 你 | E4 BD A0(3 字节) | %E4%BD%A0 |
| 好 | E5 A5 BD(3 字节) | %E5%A5%BD |
| 空格 | 20(1 字节) | %20 |
| A | 41(1 字节) | A(不用编码) |
| & | 26(1 字节) | %26 |
关键认知:百分号编码编的是「字节」,不是「字符」。所以一个中文通常变成 3 个 %XX,而英文字母保持原样。
RFC 3986 把 ASCII 字符分成三类,决定了「能不能原样放进 URL」。
| 类别 | 包含哪些 | 要不要编码 | 说明 |
|---|---|---|---|
| 未保留字符 unreserved |
A-Z a-z 0-9 - _ . ~ | 永远不用编码 | 到哪儿都安全,可以原样出现。 |
| 保留字符 reserved |
:/?#[]@ !$&'()*+,;= | 看场合 | 它们有结构含义。当结构用时保留原样;当普通内容用时必须编码。 |
| 其它 / 不安全 | 空格、" < > \ ^ ` { } |、控制字符、所有非 ASCII(中文等) | 必须编码 | 在 URL 里非法,一律 %XX。 |
最重要的一句话:同一个字符在不同位置,处理方式不一样。比如 ? 出现在「参数开始」时是骨架,保留;但如果某个参数值里真的要写一个问号,就必须写成 %3F,否则会被误认为是查询串的开始。
这是理解百分号编码最容易卡住的地方 —— 规则不是「全 URL 统一」,而是按段的。
| 部分 | 例子 | 可以原样保留的字符 |
|---|---|---|
| 协议 scheme | https: | 字母 数字 + - . |
| 主机 host | example.com | 字母 数字 - . ~ % 及部分 sub-delims |
| 路径 path | /搜索/结果 | 未保留字符 + :@ 及 /(作分隔)+ sub-delims |
| 查询 query | ?q=你好&page=2 | 未保留字符 + /?&=(作结构)+ sub-delims |
| 锚点 fragment | #第3节 | 同 query,另加 # 本身 |
所以正确做法是「分段编码」:一条 URL 要编码时,应当把协议、主机、路径的每一段、参数名、参数值分别编码,再用结构符号拼起来 —— 而不是把整条 URL 一次性丢进编码器(那样 :// ? & 会被编掉,网址就坏了)。
把 https://example.com/搜索?q=你好 world 变成合法 URL。
原始:https://example.com/搜索?q=你好 world
# 按段拆开、分别编码,结构符号保留:
协议 https: → 不变
主机 example.com → 不变
路径 /搜索 → /%E6%90%9C%E7%B4%A2
参数名 q → 不变
参数值 你好 world → %E4%BD%A0%E5%A5%BD%20world
结果:https://example.com/%E6%90%9C%E7%B4%A2?q=%E4%BD%A0%E5%A5%BD%20world注意:: // ? = 都保持原样,只有「内容」部分的中文和空格被编码了。
本页为概念讲解,不含任何请求与上传 · 静态页面,打开即可读。