简体中文

开发者工具 · URL 编码器和解码器

为什么 + 在解码查询字符串时会变成空格,而在解码查询字符串时则不会

· 工作原理

url 编码 JavaScript 开发人员工作流程

加号及其百分比编码形式在不同的解码器中保持不同
原始 ToolAcre 矢量图

+ 是否表示空格取决于您调用哪个解码器。这篇文章解释了decodeURIComponent、URLSearchParams和服务器框架如何处理+,以及如何避免将真正的加号变成空格。

为什么 + 在解码查询字符串时会变成空格,而在解码查询字符串时则不会

HTML 表单提交使用 application/x-www-form-urlencoded 格式,其中空格变为加号。接收 name=Alice+Smith 的服务器在提取值之前将每个加号替换为空格。当实数加号属于数据时,例如在计算 5+3 中,它在形式解码步骤之后以 5 3 形式到达服务器。这种无形的转换是混乱的根源。

JavaScript 解码会根据您使用的函数产生不同的结果。 URLSearchParams 将加号视为空格,以匹配服务器行为。但decodeURIComponent 保持 plus 不变,按字面意思对待它。函数之间的这种不对称性就是相同输入解码不同的原因。期望两个解码器产生相同结果的开发人员发现他们没有。

两种看起来相似的编码 — RFC 3986 百分比编码与应用程序/x-www-form-urlencoded

两种编码标准看起来相似,但工作方式不同。 RFC 3986 定义百分比编码:任何字符都变为 %HH。空间变为 %20。 application/x-www-form-urlencoded 标准添加了一个简写:空格可以加。两者都适用于表单上下文,但 plus 是可选的并且特定于该标准。它们是具有相似外观的不同域。

调用decodeURIComponent 仅适用于RFC 3986 解码。它将 %20 读作空格,将 plus 读作文字加。 URLSearchParams 应用表单解码规则:百分比转义符变为字符,加号变为空格。这两个函数在不同的领域解决相同的问题。混合它们会导致真正的加号消失,或者空间变成加号但无法转换。

decodeURIComponent 单独留下 + ; URLSearchParams 将其变成一个空格——两种 JavaScript 行为的比较

服务器行为各不相同,这使问题更加复杂。 Rails 或 Django 自动应用格式规则:加号变为空格。但是使用 URL 解码器提取并手动解码原始查询字符串会使 plus 保持不变。相同的值经过不同的框架处理会产生不同的结果。服务器代码通常会隐式处理此问题,隐藏问题,直到您编写自定义解码器。

示例:电话号码字段存储 +1-555-0100,其中加号作为国家/地区代码。 HTML 表单将其编码为 %2B1-555-0100 因为 JavaScript 将 plus 编码为 %2B。服务器收到此消息。如果应用形式解码,%2B 变为正值,该值是正确的。如果代理剥离编码,则对结果调用decodeURIComponent会生成+1-555-0100。每层解码一次。

服务器做什么——查询字符串和请求正文中的常见框架行为,以一般术语描述

JavaScript 可以使用encodeURIComponent 对值进行编码。给定 a+b,它产生 a%2Bb。当该编码字符串到达​​服务器或表单感知解码器时,%2B 解码为加号,并且结果是正确的。如果您使用格式规则进行编码,则空格将变为加号,而实数加号将变为 %2B。无论哪种方式,编码都会产生%2Bb。解释取决于应用哪种解码规则。

测试往返:从 a+b 开始。使用encodeURIComponent 进行编码以获得%2Bb。使用decodeURIComponent解码a%2Bb并恢复a+b。将 a+b 传递给 URLSearchParams:它将加号视为空格,生成 b。将 a%2Bb 传递给 URLSearchParams 以获取 a+b。根据您使用的解码器,相同的输入以两种方式解码会产生不同的输出。

工作示例:通过两个解码器的“a+b”和“a%2Bb”——表中的四个结果

常见错误如下。开发人员使用decodeURIComponent 进行解码,并想知道为什么带有实数加号的传入表单数据会中断。他们应该使用 URLSearchParams。相反,有人在应该使用decodeURIComponent 时使用了URLSearchParams,并且每个文字加号都消失了。编码两次会产生 %252B,需要匹配的编码器-解码器对才能正确解码。

另一个错误是手动将查询字符串构造为 ?q=value 而不进行编码。值中的任何“&”或等于都会默默创建一个新参数。浏览器不会事后猜测连接;它将结果视为正确形成的。只有使用encodeURIComponent 进行有意编码才能防止这种情况发生。 URL 编码器和解码器显示了所有三个函数,揭示了每个函数产生的结果。

常见错误 — 解码两次,或在路径段中将空格编码为 +

表单编码规则称为 application/x-www-form-urlencoded 因为它描述了 HTTP 请求正文 Content-Type 标头。没有文件上传的 HTML 表单以此格式发送正文。 URL 中的查询字符串也使用此约定,尽管从技术上讲它们没有官方编码标准。 URL 规范将查询视为不透明; plus 的含义不是强制的。但在 Web 应用程序中,加号通常意味着空格。

为了保证正确的行为,请谨慎编码并使用匹配函数进行解码。如果使用encodeURIComponent 进行编码,请使用decodeURIComponent 进行解码。如果读取 HTML 表单数据或表单格式的请求正文,请使用 URLSearchParams。永远不要根据外表来猜测。像 a+b 这样的字符串是有歧义的。解码器不可互换。

这不包括什么 - 多部分表单数据和 JSON 请求主体

多部分表单数据、JSON 请求主体和其他标准具有单独的编码规则。 JSON 不使用加号进行空格或百分比编码;它使用 Unicode 转义。多部分使用不同的边界。本文仅涵盖查询字符串和表单编码主体,因为这就是加号歧义出现的地方。请务必检查 Content-Type 标头和定义它的 RFC。

当文字加号属于查询值时,始终将其编码为 %2B。 URL 编码器和解码器显示了如何在组件模式下将加号保护为 %2B,与成为 %20 的空格分开。将 a+b 和 a%2Bb 通过每种模式,然后检查结果。该比较说明了为什么相同的输入解码不同。区别在于两个不同标准的正确行为。

要点:始终将文字加号编码为 %2B — URL 编码器和解码器如何将值显示为百分比编码查询值

要点:查询字符串中的加号是空格的形式编码简写,而不是文字加号,除非它来自将其保护为 %2B 的编码。错误的解码器会失去这种保护。 URLSearchParams 在现代 JavaScript 中是最安全的;它处理表单编码并提供命名参数访问。对于原始字符串,encodeURIComponent 会保护一切; debugURIComponent 解释 %20 和百分比,但按字面意思处理加号。

测试一下:手动构建 ?x=a+b 并将其粘贴到 URL 编码器和解码器中。检查它并观察 URLSearchParams 将其拆分为值为 a b 的参数 x。粘贴 ?x=a%2Bb 并查看值 a+b。使用encodeURIComponent 构建URL 并进行比较。这种视觉确认澄清了规则:表单规则使用加号,百分比编码使用 %20,混合它们就是加号消失在空间中的原因。