首页/开发/正则与编码速查/URL 保留字符该不该编码

URL 保留字符该不该编码

URL 保留字符该不该编码取决于用途:作为分隔符时必须保持原样,作为数据时必须编码;未保留字符永不编码,百分号自身作为数据要写成 %25,混用会造成参数被拆分或签名不一致。

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

保留与未保留的分界

RFC 3986 把字符分成三类:未保留字符(字母、数字与 - . _ ~)在 URI 中永远不需要编码;保留字符分为通用分隔符(: / ? # [ ] @)与子分隔符(! $ & ' ( ) * + , ; =),它们在 URI 中承担语法作用;其余字符必须编码。判断原则是「这个字符在当前位置是结构还是数据」:作为结构必须原样保留,作为数据必须转义。参数值里的 & 与 = 属于典型数据,必须编码,否则会被解析成新的参数。

基本信息

未保留字符字母、数字、- . _ ~,不需要编码
通用分隔符: / ? # [ ] @,构成 URI 结构
子分隔符! $ & ' ( ) * + , ; =,常见于查询串语法
核心规则作结构保留原样,作数据必须编码
百分号本身作为数据时写作 %25
实践要点逐参数编码,而不是编码整条 URL

典型使用场景

  • 参数值含特殊字符:搜索词里有 & 或 =,必须编码才能正确传递
  • 路径参数:包含斜杠的值需要编码或改用查询参数承载
  • 签名计算:签名基串按规范编码,任何多编或少编都会校验失败
  • 网关与代理规则:改写规则需理解保留字符语义,避免破坏结构
  • 安全校验:参数注入与路径穿越常通过未编码或重复编码实现

编码与组装示例

编码与组装示例
# 逐参数编码后组装:值里的 & 与 = 会被正确转义
python -c "import urllib.parse as u; print('https://e.com/s?' + u.urlencode({'q':'a&b=c', 'n':'x y'}))"
# 单独观察:哪些字符被编码,哪些保持原样
python -c "import urllib.parse as u; print(u.quote('a&b=c~-._:/'))"
# 百分号作为数据要写成 %25
python -c "import urllib.parse as u; print(u.quote('100%'), u.unquote('100%25'))"
# 路径参数含斜杠时:编码斜杠或改用查询参数
python -c "import urllib.parse as u; print(u.quote('a/b', safe=''))"

字符处理判断

字符类别作数据时
&子分隔符编码为 %26,否则会被当成参数分隔
=子分隔符编码为 %3D,否则会被当成键值分隔
+子分隔符在查询串中常表示空格,作数据需编码为 %2B
/通用分隔符路径中作数据需编码为 %2F
#通用分隔符作数据需编码为 %23,否则会被当成片段起点
- . _ ~未保留字符保持原样,编码后可能与签名不符
「多编码一次不会出错」是错误认识:对未保留字符做编码会改变字符串,而许多签名与校验流程要求严格按规范编码,结果表现为「同样的逻辑有时成功有时失败」,排查成本很高。
参数注入是常见漏洞:值里的 & 未编码就能让攻击者追加参数,覆盖服务端信任的字段。防御做法是参数值必须编码,服务端解码后再做业务校验,不要依赖客户端已编码这一假设。
组件不同规则不同:查询串与路径允许的原样字符不一样,片段与用户信息部分也有各自限制。把「一套编码函数用遍全 URL」容易在路径与片段上出错,稳妥做法是按组件分别处理。

易错点

  • 参数值里的 & 与 = 未编码:参数被拆分或产生参数注入 → 逐参数编码后再拼接
  • 对未保留字符也编码:与签名或校验规则不符,出现间歇失败 → 按规范只编码必要字符
  • 把整条 URL 交给编码函数:分隔符被转义,链接打开失败 → 只编码数据部分
  • 路径参数含斜杠未处理:被解析成路径层级,路由匹配失败 → 编码斜杠或改用查询参数
  • 只做一次编码就认为安全:校验端若再解码一次,仍可能被组合绕过 → 解码后按业务规则校验并做路径规范化

数据来源与参考

  • RFC 3986:保留字符与未保留字符定义
  • WHATWG URL 标准:URL 解析器与序列化规则
  • OWASP:参数注入与路径穿越防护建议

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

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