首页/开发/正则与编码速查/URL 百分号编码的原理

URL 百分号编码的原理

百分号编码把字符先按 UTF-8 编成字节、再对不允许出现的字节写成 %加两位十六进制;允许出现的字符集随 URL 组件不同而不同,因此编码范围要按组件确定,不能一套规则用到底。

正则与编码速查开发更新于 2026-10-17
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌​​‌​‌‌‌‌​‌‌‌​​‌​​‌‌​​‌​‌​‌‌​​‌‌‌​‌‌​​‌​‌​‌‌‌‌​​​​​‌​‌‌‌‌​‌‌‌​​​​​‌‌​​‌​‌​‌‌‌​​‌​​‌‌​​​‌‌​‌‌​​‌​‌​‌‌​‌‌‌​​‌‌‌​‌​​​​‌​‌‌​‌​‌‌​​‌​‌​‌‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​​‌​​​‌‌​‌​​‌​‌‌​‌‌‌​​‌‌​​‌‌‌​​‌​‌‌​‌​‌‌‌​​​​​‌‌‌​​‌​​‌‌​‌​​‌​‌‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌​​‌​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​‌​‌​​‌​‌‌‌​​‌‌​‌​​​​‌‌‌​‌​​​‌‌​‌‌​‌​‌‌​‌‌​​

编码过程与允许集

百分号编码分两步:把字符按字符编码(现代 Web 事实标准是 UTF-8)转成字节,再把每个不属于当前组件允许集的字节写成 %加两位十六进制。允许集由 RFC 3986 定义:未保留字符(字母、数字与 - . _ ~)永不编码;保留字符(: / ? # [ ] @ 与 ! $ & ' ( ) * + , ; =)有语法含义,用作分隔符时保持原样、用作数据时必须编码;其余字符一律编码。理解这一点就能解释「为什么同一个参数在路径与查询串里编码结果不同」。

基本信息

形式% 加两位十六进制,如 %E4%B8%AD
字符编码来源通常按 UTF-8 编码后再逐字节转义
未保留字符字母、数字、- . _ ~,永远不编码
保留字符有语法含义,作数据时必须编码
组件差异路径、查询、片段允许的字符集不同
常用实现encodeURIComponent、urlencode、quote 等

典型使用场景

  • 拼接口参数:对参数值编码后再拼接,避免分隔符被误解析
  • 生成分享链接:中文标题与特殊符号必须编码才能安全传递
  • 签名与校验:签名前的规范化要求固定的编码规则,选错会导致签名不一致
  • 日志分析:识别被编码过的内容,避免把 %E4%B8%AD 当成普通字符串处理
  • 爬虫与抓包:还原编码内容以查看真实参数

编码示例

编码示例
python -c "import urllib.parse as u; print(u.quote('中文 值'))"            # 路径风格:空格为 %20,中文为 UTF-8 字节
python -c "import urllib.parse as u; print(u.quote_plus('中文 值'))"        # 表单风格:空格为 +
python -c "import urllib.parse as u; print(u.quote('中', encoding='gbk'))"   # 不用 GBK 生成 URL
# 按参数逐个编码再拼接,不要编码整条 URL
python -c "import urllib.parse as u; print('https://e.com/s?' + u.urlencode({'q':'中文 & 值'}))"
# 解码还原
python -c "import urllib.parse as u; print(u.unquote('%E4%B8%AD%E6%96%87'))"  # 中文

字符类别与处理

类别示例处理方式
未保留字符A z 0 9 - . _ ~永不编码
保留字符(作分隔符): / ? # & =保持原样以维持结构
保留字符(作数据)参数值中的 & = +必须编码为 %XX
百分号自身%作为数据时编码为 %25
非 ASCII 字符中文、emoji先按 UTF-8 编成字节再逐字节转义
控制字符换行、制表必须编码,禁止出现在 URL 中
编码发生在字节层:同一个字符在不同源编码下转义结果不同。历史上用 GBK 生成 URL 编码会得到 %D6%D0 之类的序列,现代系统按 UTF-8 解码就会失败或乱码,因此不要用非 UTF-8 编码生成 URL 内容。
编码与安全直接相关:参数值里的 & 与 = 若未编码,会被解析成新的参数(参数注入);路径里的 .. 与编码变体可能绕过路径校验。服务端应解码后再校验,并对已解码路径做规范化。
签名场景要求编码规则完全一致:OAuth 等规范对哪些字符编码、空格用哪种形式都有明确规定,实现时不能凭直觉替换成「等价的 %20 或 +」,否则签名校验会以「部分请求失败」的形式间歇报错。

易错点

  • 对整条 URL 编码:分隔符被转义,链接结构被破坏 → 只编码参数值与需要编码的片段
  • 用非 UTF-8 编码生成转义序列:现代解析端按 UTF-8 解码失败或乱码 → 统一按 UTF-8 生成
  • 参数值未编码直接拼接:& 与 = 造成参数注入或值被截断 → 逐参数编码后再拼
  • 空格编码方式选错:路径里的 + 不是空格,参数解析与预期不符 → 明确位置与上下文选择 %20 或 +
  • 签名与请求使用不同编码规则:签名偶尔校验失败,排查困难 → 按规范固定编码规则并覆盖测试

数据来源与参考

  • RFC 3986:URI 通用语法与百分号编码
  • WHATWG URL 标准:URL 解析与序列化
  • HTML 表单规范:application/x-www-form-urlencoded 编码规则

整理校对:其其网ICT文档中心 · 本页地址:docs.qiqicto.com/regex/percent-encoding-principle.html

​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌​​‌​‌‌‌‌​‌‌‌​​‌​​‌‌​​‌​‌​‌‌​​‌‌‌​‌‌​​‌​‌​‌‌‌‌​​​​​‌​‌‌‌‌​‌‌‌​​​​​‌‌​​‌​‌​‌‌‌​​‌​​‌‌​​​‌‌​‌‌​​‌​‌​‌‌​‌‌‌​​‌‌‌​‌​​​​‌​‌‌​‌​‌‌​​‌​‌​‌‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​​‌​​​‌‌​‌​​‌​‌‌​‌‌‌​​‌‌​​‌‌‌​​‌​‌‌​‌​‌‌‌​​​​​‌‌‌​​‌​​‌‌​‌​​‌​‌‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌​​‌​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​‌​‌​​‌​‌‌‌​​‌‌​‌​​​​‌‌‌​‌​​​‌‌​‌‌​‌​‌‌​‌‌​​