encodeURI 和 encodeURIComponent 有什么区别?
encodeURI 用于编码完整的 URL,会保留 /、? 和 # 等结构性字符。encodeURIComponent 用于编码单个 URI 组成部分,会对包括 /、? 和 & 在内的所有特殊字符进行编码。查询参数值应使用 encodeURIComponent,完整 URL 应使用 encodeURI。
什么是 encodeURI()?
encodeURI() 是 JavaScript 的内置函数,用于编码一个完整的统一资源标识符(URI)。它会把在 URI 中不合法的字符转换为对应的 percent-encoding 形式,但会有意保留那些在 URI 中具有结构含义的字符。
具体来说,encodeURI() 不会编码以下字符:A-Z a-z 0-9 ; , / ? : @ & = + $ - _ . ! ~ * ' ( ) #。这意味着编码之后 URL 的整体结构依然保持完整。
// encodeURI() 会保留 URL 结构
const url = 'https://example.com/my page?name=John Doe&city=New York';
console.log(encodeURI(url));
// "https://example.com/my%20page?name=John%20Doe&city=New%20York"
// 注意::、/、?、& 和 = 都没有被编码
正是这种行为,使得 encodeURI() 非常适合处理这样一种情形:你有一个完整的 URL,其中可能包含空格或非 ASCII 字符,但其结构性字符(协议分隔符、路径分隔符、查询字符串标记)应当原样保留。
什么是 encodeURIComponent()?
encodeURIComponent() 用于编码 URI 的单个组成部分,例如查询参数值或路径片段。与 encodeURI() 不同,它几乎会编码所有特殊字符,包括那些在 URL 中具有结构含义的字符。
encodeURIComponent() 唯一不会编码的字符是:A-Z a-z 0-9 - _ . ! ~ * ' ( )。除此之外的所有字符,包括 /、?、&、=、# 和 :,都会被进行 percent-encoding。
// encodeURIComponent() 会编码除非保留字符之外的所有字符
const value = 'Tom & Jerry / Friends?';
console.log(encodeURIComponent(value));
// "Tom%20%26%20Jerry%20%2F%20Friends%3F"
// 注意:&、/ 和 ? 都被编码了
// 构建带查询参数的 URL
const url = 'https://example.com/search?q=' + encodeURIComponent(value);
// "https://example.com/search?q=Tom%20%26%20Jerry%20%2F%20Friends%3F"
由于它会编码结构性字符,因此你绝不应该对一个完整的 URL 使用 encodeURIComponent()。这样做会把 ://、所有 / 路径分隔符以及 ? 查询分隔符全部编码掉,导致 URL 无法使用。
核心区别一览
| 特性 | encodeURI() | encodeURIComponent() |
|---|---|---|
| 用途 | 编码完整的 URI | 编码 URI 的组成部分 |
编码 / |
否 | 是(%2F) |
编码 ? |
否 | 是(%3F) |
编码 & |
否 | 是(%26) |
编码 = |
否 | 是(%3D) |
编码 # |
否 | 是(%23) |
编码 : |
否 | 是(%3A) |
| 编码空格 | 是(%20) |
是(%20) |
| 编码 Unicode | 是 | 是 |
何时使用哪个函数
规则很简单:当你想编码一个完整 URL 并保持其结构有效时,使用 encodeURI();当你想编码将要插入到 URL 中的单个值时,使用 encodeURIComponent()。
// 场景 1:编码包含空格的完整 URL
const fullUrl = 'https://example.com/my documents/file name.pdf';
const encoded = encodeURI(fullUrl);
// "https://example.com/my%20documents/file%20name.pdf"
// 场景 2:从各部分拼接构建 URL
const baseUrl = 'https://api.example.com/search';
const query = 'price >= 100 & category = books';
const finalUrl = baseUrl + '?q=' + encodeURIComponent(query);
// "https://api.example.com/search?q=price%20%3E%3D%20100%20%26%20category%20%3D%20books"
// 场景 3:将重定向 URL 作为参数进行编码
const redirectUrl = 'https://example.com/callback?token=abc';
const loginUrl = 'https://auth.example.com/login?redirect=' +
encodeURIComponent(redirectUrl);
// 整个重定向 URL 被作为单个参数值进行编码
常见错误及如何避免
错误 1:用 encodeURI() 编码查询参数值。 由于 encodeURI() 不会编码 & 或 =,因此在包含这些字符的参数值上使用它,会破坏查询字符串的结构。
// 错误做法
const bad = 'https://example.com/search?q=' + encodeURI('salt & pepper');
// "https://example.com/search?q=salt%20&%20pepper"
// 服务器看到的是 q="salt " 以及一个额外的参数 " pepper"
// 正确做法
const good = 'https://example.com/search?q=' + encodeURIComponent('salt & pepper');
// "https://example.com/search?q=salt%20%26%20pepper"
错误 2:对完整 URL 使用 encodeURIComponent()。 这会把所有斜杠、冒号和问号都编码掉,从而破坏 URL 结构。
// 错误做法
console.log(encodeURIComponent('https://example.com/path?key=value'));
// "https%3A%2F%2Fexample.com%2Fpath%3Fkey%3Dvalue"
// 这已经不是一个有效的 URL 了!
// 正确做法
console.log(encodeURI('https://example.com/path?key=value'));
// "https://example.com/path?key=value"(本身已经有效,没有需要编码的字符)
错误 3:重复编码。 如果一个字符串已经过 percent-encoding,再次编码就会把其中的 % 符号也编码掉,从而将 %20 变成 %2520。在应用编码函数之前,请务必检查该值是否已经被编码过。
一个更安全的现代替代方案是使用 URL 和 URLSearchParams API,它们会自动处理编码,帮你彻底避开这些陷阱。