教我尊重百分比编码的错误是一个 OAuth 重定向,恰好一个客户失败了。WP Adminify 有一个 Google Fonts 集成,可以通过 OAuth 进行身份验证,而一个用户 - 一个运行某些反向代理设置的主机经销商我仍然不't 完全理解 - 不断获得 redirect_uri_mismatch errors。else人都没事, 我花了两天的大部分时间都怪他的服务器config。然后我终于看了他浏览器发送的实际url, 一个字符一个字符, 那里是: %2520 空间应该在哪里。他的代理正在编码 redirect_uri。我的插件是 也 google 收到一个空间已经编码两次的 URL - %20 变成 %2520-并拒绝了整个握手。两行代码修复了它。两天时间找到它。
That wasn't甚至是我的第一次编码灾难。多年前I'd为插件启动构建了一个活动链接,其中包含一个原始的安培数UTM参数 - 类似 utm_campaign=black&friday。分析仪表板显示了一个名为的神秘活动 black 还有一个称为的幻象参数 friday that matched nothing。的 ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Here's关于URL编码的事情:it's那些看起来微不足道的问题之一,直到它’s 't。规则生活在2005年的规范中(RFC 3986),浏览器现实生活在不同的规范中(the WHATWG URL标准),JavaScript给你三个不同的函数,它们都做稍微不同的事情,PHP给你另外两个。弄错了,你不't得到崩溃- 你得到截断的参数,破碎的OAuth流,以及在Chrome中工作但在电子邮件客户端中死亡的链接。
所以我构建了我一直想要的编码器/解码器 Toolz.dev。本指南涵盖了如何使用它,以及 - 更重要的是 - 百分比编码实际上是如何工作的,因此下一个 %2520 在日志中,您需要两分钟而不是两天。
TL;博士: 要在线 URL 编码或解码,请将字符串粘贴到 Toolz.dev URL 编码器/解码器、挑选模式,然后点击 Encode 或 Decode,它正确处理 UTF-8 和表情符号,并且 Swap 按钮将输出反馈到输入中,这样您就可以剥离双编码值 (
%2520)一次分开一层。一切都运行客户端,因此您的 URL 中的令牌和会话 ID 永远不会触摸服务器。Encode 参数 值 具有组件模式;只有当您知道原因时才对完整 URL 进行编码。
主要特点
在一个工具中编码和解码
I需要编码一个值的时间的一半另一半I'm盯着一个日志文件中粗糙的URL,需要将其解码为可读的东西工具从一个输入框中做到- Encode和Decode彼此坐在一起作为两个按钮,所以那里's没有寻找单独的页面粘贴编码字符串并命中Decode;键入原始查询值并命中Encode它也来回干净:编码,解码,然后你把原来的字符串拿回来,字节换字节听起来很明显,但是I've使用了在线工具,在来回中破坏了加号,因为他们不能't决定他们遵循哪个规格这个是明确的关于它's在每一步都做些什么,这正是你想要的're调试。
组件与全 URL 编码模式
这种区别是大多数编码错误诞生的地方。组件模式对所有未保留的't - 包括 /、 ?、 &、和 =-这是你想要的单一参数值。full-url模式留下结构字符单独所以url仍然作为一个url工作, 这是你想要的当你're清理一个完整的地址。使用错误的要么破坏你的url结构, 要么留下危险的字符未编码。工具将两种模式在一个下拉中一键分开, 标记为JavaScript函数每一个对应 - encodeURIComponent、 encodeURI、 application/x-www-form-urlencoded。我在那个命名上来回走动。intent标签("编码一个值","编码一个整 URL")会读得更好冷,但函数名称意味着下面的参考面板将一对一映射到代码上你'即将写入,而那's大多数人实际处于的时刻。如果你'曾经打过 encodeURI 当你的意思是 encodeURIComponent- 我不止一次 - 面板在你发货之前就已经准备好了。
处理 UTF-8、表情符号和国际字符
类型 café 你明白了 caf%C3%A9- 的 é 正确扩展到其两个 UTF-8 字节。键入表情符号即可获得四个百分之百编码的字节。这是旧工具和已弃用的 JavaScript 的地方 escape() 功能崩溃:它们采用拉丁语 1 或产生非标准 %uXXXX sequences 没有服务器可以解析。如果你're构建具有用户生成内容的URL - 姓名,搜索查询,任何语言的城市名称是't英语 - 正确的UTF-8处理是't一个不错的孟加拉语文本,阿拉伯语蛞蝓,中文搜索词:所有这些编码到有效的RFC 3986百分比- 另一端解码相同的序列。
双编码值的交换按钮
的 %2520 trap - 已经编码的 %20 get encoded again - 花了我两天时间一次,所以这个是个人化的,解码是单层操作: %2520 解码为 %20而不是一个空间,因为 %25 於 的编码 %.一通一层你。交换按钮(⇄)将输出移回输入框所以下一遍就是一键走开了 I've 解包 URL 经过代理、重定向服务、邮件链接-wrapper 后三层深 - 交换、解码、交换、解码,直到字符串停止更改。那个"停止更改"时刻是你're 寻找的实际信号。诚实地说这是什么:it's 手动循环,而不是检测器。工具没有't 标志 %25XX 对你来说,我来回讨论它是否应该 - 自动解码直到稳定会很方便,直到它默默地破坏合法包含百分比符号的值。
三种模式,一种显式参考面板
模式选择器携带三个选项 - 组件、完整 URL 和表单 URLencoded - 并且下面的面板准确拼写出该模式逃逸的字符、保留的字符,并显示一个工作示例。我添加它是因为我永远不记得是否 encodeURIComponent 叶 ~ 独(确实如此)或是否 ! 並 * 存(他们确实如此,这让人感到惊讶,因为RFC 3986将他们归类为子分隔而不是无保留)。而不是记住三个JavaScript函数'怪癖,你按意图选择模式并读回它's即将做的事情。那个参考文本是我最常用的部分,它's I'd想要的东西,如果我在凌晨1点冷落到页面上。
100% 客户端 - 没有什么可以离开您的浏览器
想想你解码的网址里面的实际内容是什么's:OAuth 授权码,密码重置令牌,会话 ID,取消订阅链接中的电子邮件地址,API 密钥一些框架有帮助地塞进查询字符串。将它们粘贴到服务器端工具中,它们会落在某人's 访问日志中,绑定到你的 IP,保留给谁知道多久。toolz。dev 编码器完全在你的浏览器中运行 - 转换是几行 JavaScript 在本地执行,并且不会对你的数据提出请求。打开 DevTools 并观看网络选项卡,如果你不't 相信我。对于任何与安全相邻的东西,客户端是't 功能,它's 最小条。
免费、无注册、无限制
No帐户墙,没有做字符串转换的工具的每日配额nag,没有"升级到Pro解码1000多个字符。"我构建了toolz。dev,因为我厌倦了广告窒息的实用程序站点,用时事通讯弹出窗口中断十秒钟的任务。将其添加为书签,每天使用五十次,完成。
URL编码器和解码器的使用方法
1步:打开工具并选择你的方向
去 Toolz.dev/tools/url-encoder string 掉到左边框里,有两个动作按钮,Encode 和 Decode,粘贴后选择一个而不是先设置方向,如果您're 从可读的东西开始(搜索查询,重定向 URL you're 即将嵌入),点击 Encode。如果您're 从充满百分号的东西开始(日志条目,引用标头),点击 Decode。输出落入右侧窗格,标头中有一个复制按钮,交换和清除坐在两个动作按钮旁边。
第 2 步:选择组件、全 URL 或表单模式
编码a 价值 这将位于参数内部 - 重定向_uri、搜索项、an 之后的任何内容 = sign?使用组件模式。它编码 /、 ?、 &、和 = so你的值可以't打破周围的url。编码a 完整的 URL that只需要空格和非ascii字符清理?使用全url模式,它保留了结构字符,第三种模式,form-urlencoded,是组件编码,空格写为 + 代替 %20- 当你're手工制作时选择它 application/x-www-form-urlencoded body。注意模式也影响解码:在形式模式下, + 解码前转换回空格;在另外两个中它保持字面加号。当有疑问时:分量模式为分量,全 URL 模式为整数。
第 3 步:阅读输出并观察剩余百分比符号
Output出现在右窗格中,解码看结果是否还包含 %XX sequences - 如果是,则该值被编码不止一次,点击 Swap 将该输出移回输入,再次解码,重复直到字符串停止更改,如果输入格式错误(误差) % 后面没有两个十六进制数字,就像字面意思一样 100%),你'会得到一个显式错误而不是一个静音的半解码,这是你're调试时想要的行为。
4步:复制和验证
击复制按钮,将结果粘贴到它所属的位置对于任何重要的事情 - OAuth重定向尤其如此 - 进行最后的理智检查:将编码值粘贴回解码模式,并确认它往返于您开始时精确的三十秒验证节拍两天 redirect_uri_mismatch。
编码百分比、RFC 3986 以及为什么空间变成 %20 或 +
URL只能安全地包含一组有限的字符,其他所有东西都必须以百分比编码字节的形式偷偷带入,规则手册是 RFC 3986 (2005),并且它将角色分成两个阵营。
毫无保留的角色 永远不需要编码:字母 A–Z 並 a–z,数字 0–9的,以及四个符号-连字符 -、时期 .,下划线 _和波浪号 ~。编码这些是合法的,但毫无意义。
保留字符 URL 内有结构作业: : / ? # [ ] @ (一般分界线)和 ! $ & ' ( ) * + , ; = (分隔符),冒号把方案和主机分开,问号启动查询字符串,安培数把参数分开,保留字符是否需要编码完全取决于 它出现的地方. A / 路径中有结构;一个 / redirect_uri参数值里面就是数据,它必须成为 %2F 或者服务器会错误地解析您的 URL。
的机制:取字符,得到它的UTF-8字节(s),并将每个字节写为 % 后面跟着两个十六进制数字。ASCII 字符是一个字节 - 空间是 %20,安培数是 %26.但UTF-8是多字节编码,所以 é 是两个字节: %C3%A9.一个典型的表情符号是四个字节- 编码为 %F0%9F%9A%80.这就是为什么假定一个字符等于一个字节的工具会破坏普通英语之外的任何东西。
现在,空间问题--URL 编码中最令人困惑的一件事。根据 RFC 3986,空间变成了 %20。但 HTML 表单提交使用不同的序列化, application/x-www-form-urlencoded的,今天定义在 WHATWG URL 标准、和 那个 格式将空间编码为 +.二者都是正确的- 在各自的语境中.这意味着 + in查询字符串是模棱两可的:它可能是字面加号(rfc 3986读取)或编码空间(表单编码读取)如果你'曾经看到一个电话号码到达为 1234 5678 当有人发送时 +1234...,你've遇到了这个bug我的建议:总是发出 %20 为空间和 %2B 对于字面加号。没有人会误解这些。
JavaScript给你三个函数,它们不可互换,给定字符串 a=b&c d:
const s = "a=b&c d";
encodeURIComponent(s); // "a%3Db%26c%20d" — encodes =, &, and space
encodeURI(s); // "a=b&c%20d" — leaves = and & alone
escape(s); // "a%3Db%26c%20d" — deprecated; breaks on Unicode
encodeURIComponent 编码除未保留字符(加)之外的所有内容 !'()*-遗留的怪癖),使其对参数值安全。 encodeURI 保留保留的字符,以便完整的 URL 保持功能 - 但这也意味着它 won'tx2019;,2019年10月1日,中国人民政治协商会议第三次会议召开,中国人民政治协商会议第三次会议召开 保护一个 & 在你的数据内。和 escape() 被弃用是有充分理由的:它产生非标准 %uXXXX 非拉丁-1字符的序列。切勿在新代码中使用它。
PHP镜像相同的分裂与一个扭曲: urlencode() 产生表单样式编码(空格变为) +),而 rawurlencode() 遵循 RFC 3986(空间变为 %20)。如果你're为除表单POST主体之外的任何其他内容构建URL, rawurlencode() 是你想要的,我很早就发出了错误的wp管理代码;wordpress's自己的 add_query_arg() I'比我还多救了我,想承认。
最后是双编码陷阱。 %20 是一个空间,编码。编码 那个字符串 又和 % 它本身就变成了 %25、给你 %2520.解码一次,得到 %20 back - 仍然编码。每当系统的两层每个"有帮助"编码时就会发生这种情况:你的代码加上一个代理,一个重定向服务加上一个电子邮件链接包装器。阻止它的规则:精确编码一次,在值进入url之前的最后一个可能的时刻,永远不要对你没有的东西进行编码'而不仅仅是解码或生成raw。
常见用例
使用用户输入构建查询字符串
URL-搜索框,过滤器,通过GET传递的表单值-的任何时候,用户类型的文本都必须是组件编码的。用户搜索 Q&A tips 变成 ?q=Q%26A%20tips;未编码,服务器看到搜索 Q 还有一个神秘参数 A tips.开发时,我用的是 URL 编码器 写代码之前生成期望值,所以我有一个已知正确的引用来测试。it's也是解决"这个字符应该编码的最快方法?"代码审查中的参数:以组件模式粘贴它,并查看像javascript's这样的现代api URLSearchParams 自动处理此问题,您应该使用它们 - 但您仍然需要这样做 验证 当某件事发生故障时,他们的输出,这's 是一项解码工作。
调试 UTM 和活动链接
Marketing links是编码雷区。UTM值与空间,管道或安培数;链接通过一个URL缩短器,然后是一个电子邮件服务's点击跟踪器,然后一个重定向 - 每层都有一个机会编码被添加或破坏当一个活动显示错误的分析,我的第一步总是相同的:将完整的链接粘贴到解码模式,读取分析服务器实际收到的内容。十个九次的罪魁祸首在几秒钟内可见 - a raw & 分割参数,a + 这应该是字面上的加号,或者a %2520 背叛双重编码。我的 black&friday 如果 I'd 在第一天就完成了这一点,那么事件将是 11 秒的修复,而不是 11 天的数据漏洞。
OAuth 重定向_uri 和回调 URL
OAuth是编码错误变得昂贵的地方,因为提供商确实如此 精确的字符串匹配 on redirect URIs。redirect_uri 是一个完整的 URL,嵌入为另一个 URL 内部的参数值 - 因此它必须是组件编码的,恰好是一次。对其进行欠编码,并且 ? 或 & inside它打破了外层授权url。双编码它,提供者比较 https%3A%2F%2F... 反对您注册 https://... 并返回 redirect_uri_mismatch 0的进一步细节。当该错误出现时, 从您的浏览器 's地址栏中解码实际授权网址, 并将重定向_uri逐个字符与您的app 's注册值进行配对 jwt解码器 用于检查返回的令牌,您无需离开浏览器即可调试整个 OAuth 流程。
从日志和引用标头解码粗略的 URL
Server日志和引用标头都充满了百分之百编码的汤: %D0%9F%D1%80%D0%B8%D0%B2%D0%B5%D1%82 在搜索引荐器中,来自机器人流量的三重编码路径,可疑请求中的编码有效负载。解码这些是您找出实际发生的情况的方式 - 无论那个奇怪的 404 是具有西里尔查询的用户还是正在探测的脚本 ../../etc/passwd 3层编码的背后。这也正是隐私角度最重要的情况:日志URL通常包含会话令牌和电子邮件地址。在客户端工具中解码它们,而不是在某个保留自己日志的随机服务器中写了更多关于这个工作流的内容 API调试工具指南。
使用卷曲进行 API 测试
您的外壳和卷曲在 URL 编码之上形成第二个雷区。 & 背景是一个过程,bash ? zsh中触发glob扩展 - 因此一个未引用、未编码的URL在到达网络之前就以令人困惑的方式失败了我的工作流程:对工具中的每个参数值进行编码,组装URL,将其包裹在单个引号中,然后运行curl。api返回400以获取"看对,"的请求时,我从冗长的输出中解码了确切的URL(curl -v)看看真正发送了什么 - 不止一次的错误是我的终端,而不是我的API。curl's --data-urlencode flag处理post主体的编码,但对于get查询字符串你're大部分是你自己,一个可靠的编码器胜过猜测。
与非 ASCII 文本共享链接
其他语言的维基百科文章、带有当地地名的 Google 地图链接、带有孟加拉语或阿拉伯语蛞蝓的文档 URL - 从您的地址栏复制一个,您可能会得到漂亮的 统一码 形式或墙壁 %E0%A6%AC-样式字节,取决于浏览器's情绪。一些聊天应用程序和电子邮件客户端截断或破坏原始的unicode形式。在共享之前对url进行编码会产生一个纯ascii字符串,该字符串在每个信使,邮件列表和markdown渲染器中都保留下来。i've尝试过相反的方式,解码将不可读的共享链接变回人类可以在点击之前验证的东西 - 值得在转发任何到达看起来像线路噪声的东西之前完成。
encodeURICompent vs encodeURI vs escape():您应该使用哪一种?
三个功能,一个正确的默认 这里's诚实的对比:
encodeURIComponent() |
encodeURI() |
escape() |
|
|---|---|---|---|
| 编码 | 除了一切 A-Z a-z 0-9 - . _ ~ ! ' ( ) * |
除未保留 + 所有保留字符之外的所有内容 (: / ? # [ ] @ ! $ & ' ( ) * + , ; =) |
除了一切 A-Z a-z 0-9 @ * _ + - . / |
| 空间变成了 | %20 |
%20 |
%20 |
& 並 = |
编码(%26、 %3D) |
未编码 | 编码 |
| Unicode 处理 | 正确 UTF-8 字节 | 正确 UTF-8 字节 | 破碎 - 非标准 %uXXXX |
| 用作 | 参数值、路径段、URL 内的任何内容 | 您不想要重组的完整 URL' | 没什么 |
| 状态 | 标准,推荐 | 标准、利基 | 弃用 |
我的立场,以及 I'会死在这座山上: 用 encodeURIComponent 对于价值观,几乎总是如此。 心智模型很简单--如果字符串正在运行的话 里面 url(一个查询值,一个路径段,一个重定向_uri),it's一个组件,它得到 encodeURIComponent. 凡是的案例 encodeURI 是真正正确的很少见:你有一个完整的、已经结构化的网址,其中包含空格或非ASCII字符,你想在不触摸它的结构的情况下对其进行清理。那's也许是现实世界中5%的编码调用。和 escape() 2010年左右之后编写的代码中根本不应该出现 - 它的Unicode输出是't有效的百分比编码,无论如何,每个现代linter都会标记它。
还有一个细微差别: encodeURIComponent 叶 ! ' ( ) * unencoded 的历史原因,即使 RFC 3986 将它们列为保留的子分隔符,对于 OAuth 和严格解析的 API,有些库添加了第二个通行证来编码这五个也。如果一个挑剔的 API 拒绝了你的值,那么's 一个地方可以看 - 以及 URL编码器's 组件模式会准确显示转换了哪些字符,以便您可以进行比较。
常见问题
URL编码是什么?
URL编码(percent-encoding)是用于在URL中表示字符的机制,否则这些字符将不安全或结构上有意义。每个有问题的字符都转换为其UTF-8字节,每个字节写为一个百分号后跟两个十六进制数字-一个空格变为%20,一个被写入的符号变为%26。规则在RFC 3986中定义。它的存在是因为URL只允许有限的字符集,而像?和&这样的字符在URL结构内部有作业要做。
为什么空间有时会变成 %20,有时会变成 +?
2种不同的规范,管理URL本身的RFC 3986将一个空间编码为%20,HTML表单提交所使用的应用程序/x-www-form-urlencoded格式,在WHATWG URL标准中定义,将一个空间编码为+。两者都在自己的上下文中有效,这就是为什么查询字符串中的+是模糊不清的。安全做法:总是为空间生成%20,为文字加号生成%2B- 每个解析器都正确处理这些。
encodeURI 和 encodeURIComponent 有什么区别?
encodeuricomponent 对几乎所有内容进行编码,包括/、?、& 和 =,对于放置在 URL 内的各个值来说是安全的。encodeURI 保留了这些保留的字符,因此完整的 URL 保留其结构。将 encodeURIComponent 用于参数值和路径段(几乎是每个现实情况),并且仅在清理完整 URL 时才对包含 & 的值使用 encodeURI 将默默地破坏您的查询字符串。
如何修复双编码 URL?
当已经编码的字符串再次被编码时,就会发生双重编码 - %20 变成 %2520,因为 %20 本身变成 %25。要修复它,请重复解码字符串,直到没有 %XX 序列保留并且输出停止更改。然后找到系统中的哪一层编码两次 - 通常是您的代码加上代理、重定向服务或电子邮件链接包装器 - 并删除其中一个编码步骤。规则:在值输入 URL 之前的最后一刻精确编码一次。
在线工具中解码 URL 是否安全?
仅当工具运行客户端时。 URL 经常包含 OAuth 代码、密码重置令牌、会话 ID 和电子邮件地址。服务器端工具接收所有这些并可能无限期地将其保留在访问日志中。toolz。dev URL Encoder/Decoder 使用 JavaScript 在浏览器中执行所有转换 - 任何地方都不会传输数据,您可以在浏览器中验证这些数据's 网络选项卡。对于任何包含凭据或令牌的内容,客户端处理应该是不可协商的。
我需要对整个网址或参数进行编码吗?
Data部分- 个别参数值以及,偶尔还有路径段即可,URL本身的结构字符(方案后的://、?开始查询、参数之间的&)必须保持未编码或URL停止工作,用组件式编码分别对每个值进行编码,然后将URL围绕它们进行组装,只有当该URL本身正在成为另一个URL内部的值时,编码一个完整的URL端到端才是正确的,就像OAuth重定向_uri。
URL编码可以处理表情符号和非英语字符吗?
是 - 现代的百分比编码在UTF-8字节上运行,因此任何Unicode字符都可以工作。像é这样的两个字节字符变成%C3%A9,四个字节的表情符号变成四个百分比序列,例如%F0%9F%9A%80。问题只出现在遗留工具或JavaScript's弃用的转义()函数中,该函数假设单字节编码并产生无效输出。toolz。dev编码器在两个方向上正确处理完整的UTF-8。
当参数包含一个 ampersand 时,为什么我的 URL 会损坏?
因为&是参数之间的分隔符。如果一个值包含原始的 ampersand - say utm_campaign=black&friday - 服务器将其解析为一个名为 utm_campaign 的参数,值为 black,加上第二个参数名为 friday。不会出现错误;您的数据只是默默地错误。将 ampersand 编码为值内部的 %26,参数完好无损。这是最常见且最不可见的 URL 错误之一。
URL中%2F是什么意思?
%2F是百分之百编码的前向斜杠。你'll看到当一个恰好包含斜杠的值- 文件路径、像07/07这样的日期或嵌套的URL- 在被放置在查询参数或路径段之前被正确编码时。请注意,出于安全原因,某些服务器和代理(Apache、较旧的Tomcat版本、各种API网关)拒绝或默默解码路径中的%2F,因此如果带有编码斜杠的请求返回404,服务器端配置通常是罪魁祸首,而不是你的编码。
I URL 如何在 Python、PHP 或命令行中进行编码?
Python:路径段的urllib。parse。quote()和表单样式查询值的quote_plus()。php:rawurlencode()产生空间为%20的RFC 3986输出,而urlencode()产生表单样式输出,具有+。命令行:jq -rR @uri或curl's -data-urlencode标志。这些中的每一个都与此工具的组件样式行为相匹配,因此您可以在此处原型编码并验证您的代码产生字节相同的输出。
包裹起来
URL编码,是小技能,收益超大,一旦可以读 %C3%A9 作为一个 é 和地点 %2520 为双编码气味,一整类"它适用于我的机器"bug- 破碎的OAuth流,幻象UTM活动,拒绝看起来完全合理的请求的API- 从神秘变成机械的规则适合索引卡:无保留的字符通过,其他一切都变成UTF-8字节作为%HH,编码值而不是结构,并且精确编码一次。
保持 URL编码器/解码器 书签在其兄弟姐妹旁边 - Base64 转换器 对于其他编码方案,您'将在每个 auth 标头中相遇(I've 编写了完整的内容 Base64 编码指南 关于何时使用哪个), HTML 实体编码器/解码器 对于 Web 内容喜欢堆叠在顶部的第三个编码层(the HTML 实体指南 盖我所打的同一个陷阱的双逃版本 %2520),以及 json格式化程序 对于解码后的 URL 所指向的任何内容。
如果您'重新组装更广泛的基于浏览器的调试套件, 编码工具指南 浏览这些工具如何在真实的工作流程中组合在一起。toolz。dev 上的一切都运行客户端,无需任何成本,并且可以很好地完成一项工作。那's 整个宣传 - 我希望有人在我花两天时间处理一个放错地方的 %25 之前向我制作了同样的宣传。



