不喜欢广告? 无广告 今天

URL 编码 什么会被转义以及为什么你的API在没有它的情况下会崩溃

发布日期
URL编码:哪些内容被转义以及为何没有编码会导致API中断 1
广告 移除?

您的API调用看起来是正确的。端点匹配,头信息无误,但响应返回了400错误请求。在盯着它看了二十分钟后,您发现了问题:查询字符串中的一个电子邮件地址包含一个 + 符号,服务器将其解码为空格。这就是URL编码的作用,而它以真正难以调试的方式破坏了系统。

本指南将介绍百分号编码实际上做了什么,哪些字符在哪些上下文中需要编码,JavaScript中大家都会遇到的陷阱,以及如何使用像 URL编码器/解码器 这样的工具来检查您的工作。

URL编码实际上做了什么

URL只能包含ASCII字符的一部分。其余内容——空格、国际字符、URL中具有特殊意义的符号——必须在传输前转换为安全格式。

百分号编码通过将每个不安全的字节替换为百分号后跟两个十六进制数字来实现这一点。空格变为 %20,井号变为 %23,正斜杠变为 %2F。名称来源于这个前置的百分号。

规范(RFC 3986)定义了“未保留字符”,这些字符无需编码:字母(A-Z,a-z)、数字(0-9)以及四个符号: - _ . ~。其余所有字符要么是保留字符(用于分隔URL结构),要么必须进行编码。

会破坏API的字符

以下是实际中造成最大破坏的字符:

字符 编码后 需要编码的上下文 笔记
空间 %20 所有上下文 也编码为 + 在表单数据中——见下文
& %26 查询字符串值 分隔查询参数;必须在值内部进行编码
= 查询字符串值 分隔键与值;在值本身中进行编码
+ 查询字符串值 在表单编码中被解码为空格——使用 %2B 表示字面意义上的加号
# %23 路径、查询字符串 标记片段;其后任何内容都不会发送到服务器
? 路径段、查询值 开始查询字符串;在路径或值中进行编码
/ 路径段(字面意义) 分隔路径段;在段值内部进行编码
@ %40 查询字符串值 查询参数中的电子邮件地址必须进行此编码

三种上下文,不同规则

您编码的URL部分决定了哪些内容需要转义。

完整URL ——当您有一个完整的URL需要传递时,您希望保留其结构。斜杠、问号和井号保持不变。只有超出允许字符集的内容需要编码。

查询字符串值 ——大多数API错误都出现在这里。查询字符串中的每个值都必须进行编码,以确保用于结构化的字符(&, =, #, +)不会在值中字面出现。如果用户姓名是“John & Jane”,查询字符串必须为 name=John%20%26%20JaneXML没有数字类型——所有内容都是文本。你的价格字段将是 name=John & Jane (服务器将其解析为两个独立的参数)。

路径段 ——路径段是斜杠之间的部分。如果段中包含斜杠(例如,包含斜杠的文件名),则必须编码为 %2F。某些服务器将 %2F 视为安全问题;在使用前请了解您的后端。

encodeURI 与 encodeURIComponent — JavaScript陷阱

JavaScript提供了两个内置的编码函数,使用错误的函数是常见的错误。

// encodeURI — encodes a full URL
// Preserves: : / ? # [ ] @ ! $ & ' ( ) * + , ; =
encodeURI("https://example.com/search?q=hello world&lang=en")
// → "https://example.com/search?q=hello%20world&lang=en"
// Note: & and = are NOT encoded — the query structure is preserved

// encodeURIComponent — encodes a single value
// Encodes everything except: A-Z a-z 0-9 - _ . ! ~ * ' ( )
encodeURIComponent("hello world&lang=en")
// → "hello%20world%26lang%3Den"
// Note: & and = ARE encoded — safe to use as a query value

// The bug: using encodeURI on a value
encodeURI("hello world&lang=en")
// → "hello%20world&lang=en"  ← & survives! Server sees two parameters.

// The correct approach for building query strings
const name = "John & Jane"
const email = "john+jane@example.com"
const url = `https://api.example.com/users?name=${encodeURIComponent(name)}&email=${encodeURIComponent(email)}`
// → "https://api.example.com/users?name=John%20%26%20Jane&email=john%2Bjane%40example.com"

经验法则:在将值放入URL之前,使用 encodeURIComponent 对单个值进行编码。只有在您有一个完整的URL并且希望清理它而不破坏其结构时,才使用 encodeURI

加号符号:表单编码与百分号编码

当HTML表单提交时带有 method="GET",浏览器使用 application/x-www-form-urlencoded对其进行编码。在此格式中,空格变为 + 而不是 %20。许多服务器框架(PHP、Django、Rails)会自动将 + 解码为空格。

当值中确实包含加号(例如电话号码 +44 7700 900000)时,就会出现问题。如果将其作为 +44...传递,服务器会将开头的加号解码为空格,得到 44...。解决方法是将字面加号编码为 %2B,这样它在两种解码方案中都能保持不变。

在现代API开发中,应坚持使用 %20 来表示空格(即 encodeURIComponent 生成的内容),而不是依赖 +.

双重编码:编码错误发生时

双重编码发生在您对已编码的内容再次进行编码时。字符串 %20 中的百分号本身会被编码为 %2520 ——服务器将 %25 解码为字面的百分号,导致您得到字符串 %20 而不是空格。

这种情况通常在以下场景中出现:

  • 您将URL存储在数据库中,并在使用前再次编码
  • 一个框架或库对您手动编码的值进行了再次编码
  • 您正在构建一个包含另一个URL作为参数的URL

为避免这种情况:在组成URL时仅编码一次。如果您不确定某个值是否已被编码,请先用 decodeURIComponent解码它,然后再干净地重新编码。

使用开发者工具调试URL编码

当API请求行为异常时,打开开发者工具(F12),转到网络标签页,点击失败的请求。在标头中找到请求URL——浏览器以编码形式显示它。在负载部分,您可以看到查询参数被解码回原始值,这有助于判断是否将与号解释为分隔符或作为字面量传递。

对于手动测试,可以使用在线URL编码/解码工具,将字符串粘贴进去,查看其编码形式——在将值嵌入请求前进行合理性检查。该 IO Tools URL编码/解码器 支持双向操作,并立即显示输出结果。

想要享受无广告的体验吗? 立即无广告

安装我们的扩展

将 IO 工具添加到您最喜欢的浏览器,以便即时访问和更快地搜索

添加 Chrome 扩展程序 添加 边缘延伸 添加 Firefox 扩展 添加 Opera 扩展

记分板已到达!

记分板 是一种有趣的跟踪您游戏的方式,所有数据都存储在您的浏览器中。更多功能即将推出!

广告 移除?
广告 移除?
广告 移除?

新闻角 包含技术亮点

参与其中

帮助我们继续提供有价值的免费工具

给我买杯咖啡
广告 移除?