为什么要对空格进行编码:encodeURI 中使用 %20,URL 中使用 +(加号) / encodeURI 和 URL 之间的区别

您可以使用 `encodeURI` 或 `URL` 对查询字符串进行编码。最近,我注意到 `URL` 对空格的编码方式不同。我将讨论为什么它们以不同的方式处理编码。在深入探讨该主题之前,我将向您展示如何使用每种方法进行编码。

用法

1. 编码URI

// 'https://www.google.com/search?q=programming%20language'
encodeURI('https://www.google.com/search?q=programming language')

您可以使用“encodeURI”函数对 URI 进行编码。但是,它不会对 URI 中有效部分的字符进行编码,因此您可能需要使用 encodeURIComponent 函数来正确编码查询字符串或 URI 中的其他组件。

例如,假设您有一个查询字符串“q”,其值为

`https://www.google.com/search?q=& 是什么意思?`。

// 'https://www.google.com/search?q=what%20is%20the%20meaning%20of%20&?'
encodeURI('https://www.google.com/search?q=what is the meaning of &?')
google search result of the url

&(ampersand)未按应有的方式转换为 `%26`。因为 &(ampersand)可以是 URI 的有效部分。因此,对查询字符串使用 `encodeURIComponent` 总是更安全。

const url = encodeURI('https://google.com/search');
const queryString = `?q=${encodeURIComponent('what is the meaning of &?')}`;
// 'https://google.com/search?q=what%20is%20the%20meaning%20of%20%26%3F';
url+queryString;
console output

由于 `encodeURIX` 和相关函数将 URI 视为字符串,因此您必须自己处理 `?` 和 `&` 等特殊字符。或者,您可以使用 `URL` 简化该过程。

2. URL

当使用 `URL` 进行编码时,需要分别处理基本 URL 和查询字符串。

console output
const url = 'https://www.google.com/search?q=programming language';
// 'https://www.google.com/search?q=programming language'
url.toString();

如果您使用“URL”构造函数一次性对所有内容进行编码,如上例所示,查询字符串可能无法正确编码。

const url = new URL('https://www.google.com/search');
url.searchParams.set('q', 'programming language');
// 'https://www.google.com/search?q=programming+language'
url.toString();
console output

通过`URL`对象的`searchParams`属性设置查询字符串,您可以设置查询字符串。

在这种情况下,空格被转换为 `+`。在解释为什么会出现这种情况之前,让我们用另一个查询字符串进行测试,看看它如何处理其他特殊字符。

const url = new URL('https://www.google.com/search');
url.searchParams.set('q', 'what is the meaning of &?');
// 'https://www.google.com/search?q=what+is+the+meaning+of+%26%3F'
url.toString();

其他特殊字符按预期进行编码。

现在,让我们深入探讨一下为什么会出现这些差异。

编码

1. 编码URI

`encodeURIX` 函数根据 RFC2396 进行编码。`URI` 不仅仅是互联网上的位置;它可以指任何类型的资源。这就是为什么它被称为 `URI`(统一资源标识符)而不是 `URL`(统一资源定位器)。

2. URL

`URL` API 根据 RFC3986 进行编码,这是一个较新的 URI 规范。

如果您需要使用“encodeURI”实现此行为,请参考此内容 - RF3986 的 encodeURIComponent 编码)。

`URLSearchParams` 按照百分比编码规则进行编码。根据文档,它用 '+' 替换空格。

虽然我在 RFC 中找不到此行为的规范,但 MDN 的 encodeURIComponent 文档指出:

对于 application/x-www-form-urlencoded,空格将被 + 替换,因此可能希望在 encodeURIComponent() 替换后再将 %20 替换为 +。

这解释了为什么 `URLSearchParams` 中的空格被“+”替换,因为它遵循 `application/x-www-form-urlencoded` 标准。

您可能已经注意到“URL”和“URLSearchParams”遵循不同的 RFC。

让我们看一些例子。

url = new URL('http://[2001:db8::1]:8080/resource?v=key:value');
// 'http://[2001:db8::1]:8080/resource?v=key:value'
url.toString();

如图所示,URL 未对括号和冒号进行编码,因为它们是 IPv6 地址的一部分。但是,冒号虽然是查询字符串的一部分,但并未编码为 `%3A`。这与百分比编码表不同。

这意味着您需要分别对 URL 和查询字符串进行编码。

url = new URL('http://[2001:db8::1]:8080/resource');
url.searchParams.set('v', 'key:value');
// 'http://[2001:db8::1]:8080/resource?v=key%3Avalue'
url.toString();
output

现在,URL 和查询字符串已被正确编码。

结论

`encodeURI`、`encodeURIComponent`、`URL` 和 `URLSearchParams` 函数各自有不同的用途,您应该根据具体需求使用它们。

`encodeURI`:根据 `RFC2396` 对 URI 进行编码。它不会对 URI 的有效部分进行编码。如果您需要根据 `RFC3986` 对 URI 进行编码,请参阅此 MDN 文档。

`encodeURIComponent`:根据 `RFC2396` 对 URI 的组成部分进行编码,例如路径、片段或查询字符串。它包括未被 `encodeURI` 编码的字符。

`URL`:根据 `RFC3986` 对 Web URL 进行编码。

`URLSearchParams`:按照 `application/x-www-form-urlencoded` 标准对参数进行编码。

如果您需要用 `%20` 替换 `+`(加号),您可以手动执行此操作,如下所示:

url.search = url.search.replace(/\+/g, '%20');

在使用 Web 开发、Restful API 或 Web URL 时,`URL` 是一个可靠的选择。此外,它遵循 `RFC3986`,比 `RFC2396` 更新。