首页 / 开发工具指南 / URL 编解码指南

URL 编解码完整指南

从 RFC 3986 标准到实际开发:一文掌握百分号编码的原理、保留与非保留字符清单、encodeURI 与 encodeURIComponent 的选择、常见编码陷阱、真实场景案例与最佳实践,帮助你正确处理 API 参数、链接分享与表单提交。

📖 阅读时长约 10 分钟 📅 更新于 2026-06-20 ✍️ 土豆丝工具团队
🔧 立即使用 URL 编解码工具
在线进行百分号编码与解码,支持中文、特殊符号与查询参数,所有计算在本地浏览器完成,保护隐私安全。
打开工具
#01

什么是 URL 百分号编码?理解 RFC 3986 的核心规则

URL 百分号编码(Percent-Encoding)最初由 Tim Berners-Lee 在 1994 年的 URI 规范中提出,随后由 RFC 3986(Uniform Resource Identifier, Generic Syntax)统一为当前版本。它解决了一个非常现实的问题:URL 只允许"未保留"的 ASCII 字符直接出现,其他一切字符——中文、表情、空格、特殊符号——都必须被"转义"。

一条 URL 可以抽象成如下结构:

scheme:[//authority]path[?query][#fragment]

其中每一层都有自己允许的字符集合,而百分号编码是它们之间的"通用接口":任何一个字符都可以写作 %XX,其中 XX 是该字符 UTF-8 编码(如果是多字节字符则是多组 %XX)的十六进制表示。

例如:

  • 空格 " " 编码为 %20;在 application/x-www-form-urlencoded 的历史约定中也可以写成 +
  • 中文"土豆"在 UTF-8 下是 0xE5 0x9C 0x9F 0xE8 0xB1 0x86,因此编码为 %E5%9C%9F%E8%B1%86
  • 保留字符 & 编码为 %26

我们的工具 中,你可以粘贴任意文本,选择"编码"或"解码",一键查看其百分号编码形式或原文字符。

#02

保留字符 vs 非保留字符:哪些字符必须编码?

RFC 3986 将字符分为两大类。理解它们的区别有助于判断何时需要编码:

① 非保留字符(Unreserved Characters)—— 永远不需要编码

A-Z a-z 0-9 - . _ ~

这些字符可以在 URL 的任意部分直接出现。如果对它们做编码也是合法的,但结果完全等价,不会带来语义上的差异。

② 保留字符(Reserved Characters)—— 必须根据上下文决定是否编码

分为两小类:

  • Generic Delimiters(分隔 URL 层级):: / ? # [ ] @
  • Sub-Delimiters(分隔参数内部结构):! $ & ' ( ) * + , ; =

它们在"作为分隔符时"必须保持原样;在"作为数据值时"必须被编码。例如:

  • ?a=1&b=2 中,& 是参数分隔符,必须保持原样;
  • 而在 ?q=Tom%26Jerry 中,用户输入的 "&" 作为值的一部分,必须编码为 %26,否则服务器会误以为多出了一个参数。

经验法则:在构造 URL 的参数值时,永远使用 encodeURIComponent,把保留字符交给浏览器/服务端去判断是否需要"去编码"。

#03

encodeURI 与 encodeURIComponent 的正确选择

浏览器原生提供了两个最常用的编码函数,但它们不可互相替换。下面是它们的对比:

① encodeURI

用途:编码一整段完整的 URL。它会保留所有"具有特殊语义"的字符,包括:: / ? # [ ] @ ! $ & ' ( ) * + , ; = - . _ ~

典型场景:你手上有一段中文或带表情的 URL,需要把它变成浏览器可以打开的纯 ASCII 形式。例如把 https://示例.com/搜索 土豆 转成 https://%E7%A4%BA%E4%BE%8B.com/%E6%90%9C%E7%B4%A2%20%E5%9C%9F%E8%B1%86

② encodeURIComponent

用途:编码单个参数值或路径片段。它会把所有"保留字符"一起编码,只剩下最少量的非保留字符(字母、数字、- . _ ~ ! ~ * ' ( ))。

典型场景:构造 ?keyword=用户输入redirect_uri=目标地址 等参数时,必须对"值"使用 encodeURIComponent。

在服务器端对应的解码函数:

  • Node.js:decodeURIComponent(...)querystring.unescape
  • Python:urllib.parse.unquote / unquote_plus
  • Java:URLDecoder.decode(value, StandardCharsets.UTF_8)
  • PHP:urldecode / rawurldecode

请注意:绝大多数服务端框架会自动对 query string 执行一次 urldecode,不要在客户端手动再 decode 一次——否则会出现"双重解码"的漏洞,例如 %2526%26&,攻击者可能构造出绕过 WAF 的注入请求。

#04

常见的编码陷阱与调试技巧

以下是生产环境中最常见的错误。一旦遇到"地址打不开、参数丢失、乱码",先检查这张清单:

陷阱 1:把整段 URL 调用 encodeURIComponent

结果是 :/? 都被编码为 %3A %2F %3F,地址变成一长串十六进制数字,浏览器无法解析为链接。正确用法:只对"参数的值"和"路径的片段"单独编码,然后再用模板字符串拼接。

陷阱 2:双重编码(Double-Encoding)

典型现象:第一次把 "Tom & Jerry" 编码为 "Tom%20%26%20Jerry",然后有人又把它当作字符串再 encode 了一次,得到 "Tom%2520%2526%2520Jerry"。服务端解码一次后得到的仍然是带 % 的字符串,导致参数值错误。解决方案:编码只发生一次,且由"最靠近输入源的那一层"负责。

陷阱 3:空格被编码为 + 而非 %20

+application/x-www-form-urlencoded 的历史约定,严格来说它不是 RFC 3986 的一部分。在 path、query 的一般位置、或 OAuth 签名算法中,空格必须使用 %20。在调试接口时,如果参数值里包含空格,先用浏览器开发者工具查看原始 query。

陷阱 4:用 decodeURI 解码 encodeURIComponent 的结果

decodeURI 只接受"看起来像完整 URL"的字符串,一旦中间出现 %2F%3F 之类的编码,它会认为其中包含"不合法的保留字符编码"并抛出 URIError。正确做法:解码 encodeURIComponent 的输出,始终使用 decodeURIComponent。

调试小技巧

  • 复制浏览器地址栏的 URL 到 在线工具,选择"解码",查看原始值是否符合预期;
  • 在 Chrome DevTools 的 Network 面板中,查看请求的 Query String Parameters 的"view parsed"与"view encoded",确认是否发生了双重编码;
  • 对于 OAuth 1.0a、URL-Safe Base64 等特殊场景,注意它们各自的"URL-Safe"字符表——例如 + → -/ → _,这类替换是另一种规则,不能与普通百分号编码混淆。
#05

真实系统中的应用案例:API、OAuth 与深度链接

下面是几种在真实系统中必须正确处理 URL 编码的典型场景。

案例 1:REST API 查询参数

当用户搜索 "Tom & Jerry" 时,如果直接拼接字符串,服务端看到的会是 ?q=Tom&Jerry,这意味着 q 的值只到 "Tom" 为止,后面被当成了另一个参数 Jerry。正确方式:

const url = `/search?q=${encodeURIComponent(keyword)}`;

案例 2:OAuth 2.0 的 redirect_uri

授权服务器要求 redirect_uri 必须与注册时完全一致(精确字符串匹配)。客户端在发送请求时必须对 redirect_uri 本身再执行一次 encodeURIComponent,于是它会出现在查询参数里变成形如 https%3A%2F%2Fapp.example.com%2Fcallback 的形式。常见错误:忘记编码导致授权服务器返回 "invalid_redirect_uri"。

案例 3:移动端深度链接(Deep Link)

当 WebView 跳转到 myapp://product?id=123&ref=search 时,"ref" 的值如果包含空格、&、中文等,必须再次编码,否则 iOS / Android 的解析器会在第一个 & 处截断。典型模式:先对每个字段值 encodeURIComponent,再以 & 串联,最后拼到 scheme 之后。

案例 4:重定向攻击与 Open Redirect

一个看似不相关的风险:如果服务器接受一个 redirect 参数且不做校验,攻击者可以构造 ?redirect=//evil.com 把用户重定向到钓鱼站。编码本身不解决这个问题,但正确的编码 + 严格的白名单校验(仅允许跳转至受信任域名的路径)是行业推荐的组合方案。

#06

多语言、特殊符号与 UTF-8 的影响

现代 URL 规范中,字符的编码一律使用 UTF-8。在大多数编程语言与框架中,这是默认行为,但仍然需要注意几个细节:

① 非 ASCII 字符一定被编码

所有汉字、日文假名、emoji、希腊字母、重音符号等,都必须写成 %XX%XX... 的形式。例如:

  • 汉字"你好" → %E4%BD%A0%E5%A5%BD
  • emoji "🎉" → %F0%9F%8E%89(4 个字节,对应 4 组 %XX)

② 不要假设"长度 = 字符数"

一个中文在 URL 中占 9 个字符(3 字节 × 3 个字符:例如 %E4%BD%A0)。在有限制的 URL 长度环境中(例如旧版 IE 的 2083 字符上限、部分 WAF 的 header 长度限制),长中文参数可能触发截断。建议:

  • 对极长参数改用 POST body 传输;
  • 如必须放在 URL 中,先对字符串做 base64 编码再 percent-encode;
  • 始终检查服务端的 max-query-string 配置。

③ 国际化域名(IDN / Punycode)

域名中含有中文时(例如 示例.com),浏览器内部会先把它转成 Punycode 形式 xn--fsq668b.com,然后再进行 DNS 查询。这一步与"路径/查询参数的百分号编码"是两套独立的机制,不要混淆:

  • 域名 → Punycode(xn--...);
  • 路径/查询 → Percent-Encoding(%XX)。

在使用 我们的在线工具 时,如果粘贴了完整的中文 URL,它会正确地把路径与查询部分编码为 %XX,而保留域名中的"."、"/"、"?"等结构字符。

#07

数据安全与隐私:为什么选择本地处理的在线工具

URL 往往携带敏感信息,包括但不限于:内部 API 路径、用户 ID、重定向目标、OAuth state、搜索关键词等。一旦把这些内容发送到第三方服务器,就可能被记录、被分析、被用于广告追踪。

我们的工具遵循"纯前端运行"的原则:

  • 所有编码/解码逻辑直接调用浏览器的 encodeURIComponent / decodeURIComponent 或等效实现;
  • 不向任何后端发送您的输入、输出、或中间结果;
  • 不使用 localStorage、Cookie 等方式持久化任何内容;
  • 可以在断网状态下继续使用。

对于需要处理 token、内部地址、用户数据等敏感 URL 的用户,我们额外建议:

  • 在离线或受控环境中使用,或在粘贴前手动脱敏关键字段;
  • 避免在公共电脑上直接粘贴生产环境地址;
  • 不要把含敏感信息的 URL 通过社交媒体或 IM 发送给别人,改用独立的、可撤销的短链接或内部文档。

最后提醒:在选择任何在线 URL 处理工具时,先确认它不把输入数据发送到服务器。一个简单的验证方法:打开浏览器开发者工具的 Network 面板,点击"执行"后观察是否有新的请求发出——我们的工具不会。你可以通过 URL 编解码工具 亲自验证这一点。