URL 编码与解码:为开发者讲解
在 URL 里键入一个空格、一个西里尔文单词,或者一个属于你数据而非地址本身的 & 号,总得有所妥协。Web 只为一小组可预测的 ASCII 字符保证安全传输。其他一切都必须被包装成路由器、服务器和浏览器都认同的格式。那种格式就是百分号编码(percent-encoding),更常被称为 URL 编码,而本页让你直接在浏览器中双向转换文本。

百分号编码到底是什么
规则很机械、很好懂。任何不能按字面出现的字符都会被一个 % 号加上两个十六进制数字替换,这两位数字拼出该字符的字节值。空格变成 %20。加号变成 %2B。井号变成 %23。当一个字符映射到多个字节时(大多数非 ASCII 文本在 UTF-8 下都是如此),你就会得到一连串三元组:欧元符号变成 %E2%82%AC。解码则逆转这个过程,把每个三元组读回它原本的字节。
这个约定定义在 URI 规范(RFC 3986)里,而且它故意很无趣。无趣正是关键。地球上每一个行为规范的 HTTP 客户端和服务器都实现同样的规则,所以一个在某处被正确编码的链接,会原封不动地到达其他任何地方。
它为何必须存在
URL 携带着两类职责截然不同的字符。保留字符,例如 /、?、#、&、= 和 :,是结构性的。它们告诉解析器路径在哪里结束、查询字符串从哪里开始,或者一个参数在哪里停止、下一个从哪里开始。如果你的实际数据里含有这些符号之一,它就必须被编码,免得解析器把它误当成标点。一个像 A&B/2024 这样的订单编号,如果原样丢进查询字符串,会被误读成两个参数和一个路径段。
然后是不安全字符和非 ASCII 字符:空格、引号、尖括号、带重音的字母、emoji,以及任何超出纯 ASCII 范围的东西。它们没理由按字面出现在 URL 里,要么因为传输途中会被损坏,要么因为它们没有已定义的表示法。对它们编码能让链接保持干净、可预测,而不是把结果交给运气。
它在实际工作中出现在哪里
查询字符串是经典案例。你追加到 ?key=... 后面的每个值都应该被编码,好让用户输入无法破坏结构。这同样适用于以 application/x-www-form-urlencoded 提交的 HTML 表单,浏览器会自动编码字段值(并且按历史惯例,把空格变成 + 而非 %20)。你还会在以下场景遇到它:构建指向非拉丁标题页面的链接、手工拼装 API 请求、把重定向目标作为参数传递,以及调试为什么一个在地址栏里看起来没问题的请求到达服务器时却乱码了。

encodeURI 与 encodeURIComponent
JavaScript 自带两个编码函数,选错了是个常见的 bug。区别在于作用范围。encodeURIComponent 针对单独一段数据,比如一个查询值。它几乎会编码所有东西,包括保留字符 /、?、:、@、&、=、+ 和 #。当数据允许把这些符号当作普通文本时,这正是你想要的。
encodeURI 针对你打算让其继续可用的整个地址。它不动结构性字符,所以那些支撑起 URL 的斜杠、冒号和问号都得以保留。当你手上有一个完整 URL,只想清理掉空格或非 ASCII 字符时,就用它;而当你要把一个值插入更大的 URL 时,就拿出 encodeURIComponent。一条简单的经验法则:用 encodeURI 编码整个链接,用 encodeURIComponent 编码你塞进去的那些部分。
一切都留在你的机器上
这个工具完全在你的浏览器中运行。你粘贴的文本用同样的标准例程在本地编码或解码,永远不会传到服务器,这使它对令牌、签名参数或任何你宁可不发送到网络上的东西都很安全。如果你还要处理其他文本变换,Base64 转换器就在它旁边,你也可以浏览全套开发者工具,找到更多日常小帮手。
常见问题
URL 里的 %20 是什么意思?
它是一个被编码的空格。空格字符不允许按字面出现在 URL 里,所以它被替换成一个百分号加上十六进制值 20,而 20 正是空格的字节值。
为什么我有时看到加号而不是 %20?
类型为 application/x-www-form-urlencoded 的 HTML 表单数据按历史惯例把空格编码成加号。在普通的路径或查询里,空格被编码为 %20。两者在各自合适的上下文中都会解码回空格。
什么时候该用 encodeURIComponent 而不是 encodeURI?
当你要把单独一个值插入 URL 时(比如一个查询参数),用 encodeURIComponent,因为它连保留字符也会编码。当你想保留那些支撑 URL 的斜杠、冒号和问号、处理完整地址时,用 encodeURI。
URL 编码会改变我数据的含义吗?
不会。编码是完全可逆的。只要两端使用同一个字符集,对结果解码就会逐字节地还原出原始文本。
像重音字母或 emoji 这样的非 ASCII 字符是怎么处理的?
它们先被转成 UTF-8 字节,然后每个字节变成各自的百分号三元组。因此一个带重音的字母或一个 emoji 可能在编码输出中展开成好几个三元组。
我用这个工具时,文本会被发送到服务器吗?
不会。编码与解码完全在你的浏览器中进行。你粘贴的任何内容都不会被上传,所以用它处理私密或敏感字符串是安全的。
