源代码: lib/url.js
url 模块提供用于网址处理和解析的实用工具。
可以使用以下方式访问它:
import url from 'url';const url = require('url');
网址字符串是包含多个有意义组件的结构化字符串。 解析时,将返回包含每个组件的属性的网址对象。
url 模块提供了两种用于处理网址的 API:一种是 Node.js 特定的旧版 API,一种是实现了与 Web 浏览器使用的相同的 WHATWG 网址标准的新版 API。
下面提供了 WHATWG 和 旧版 API 之间的比较。
在网址 'https://user:pass@sub.example.com:8080/p/a/t/h?query=string#hash' 上方显示的是由旧版 url.parse() 返回的对象的属性。
下方则是 WHATWG URL 对象的属性。
WHATWG 网址的 origin 属性包括 protocol 和 host,但不包括 username 或 password。
┌────────────────────────────────────────────────────────────────────────────────────────────────┐
│ href │
├──────────┬──┬─────────────────────┬────────────────────────┬───────────────────────────┬───────┤
│ protocol │ │ auth │ host │ path │ hash │
│ │ │ ├─────────────────┬──────┼──────────┬────────────────┤ │
│ │ │ │ hostname │ port │ pathname │ search │ │
│ │ │ │ │ │ ├─┬──────────────┤ │
│ │ │ │ │ │ │ │ query │ │
" https: // user : pass @ sub.example.com : 8080 /p/a/t/h ? query=string #hash "
│ │ │ │ │ hostname │ port │ │ │ │
│ │ │ │ ├─────────────────┴──────┤ │ │ │
│ protocol │ │ username │ password │ host │ │ │ │
├──────────┴──┼──────────┴──────────┼────────────────────────┤ │ │ │
│ origin │ │ origin │ pathname │ search │ hash │
├─────────────┴─────────────────────┴────────────────────────┴──────────┴────────────────┴───────┤
│ href │
└────────────────────────────────────────────────────────────────────────────────────────────────┘
("" 行中的所有空格都应被忽略。它们纯粹是为了格式化。)
使用 WHATWG API 解析网址字符串:
const myURL =
new URL('https://user:pass@sub.example.com:8080/p/a/t/h?query=string#hash');
使用旧版 API 解析网址字符串:
import url from 'url';
const myURL =
url.parse('https://user:pass@sub.example.com:8080/p/a/t/h?query=string#hash');const url = require('url');
const myURL =
url.parse('https://user:pass@sub.example.com:8080/p/a/t/h?query=string#hash');
可以使用属性设置器或模板文字串从组件部分构建 WHATWG 网址:
const myURL = new URL('https://example.org');
myURL.pathname = '/a/b/c';
myURL.search = '?d=e';
myURL.hash = '#fgh';
const pathname = '/a/b/c';
const search = '?d=e';
const hash = '#fgh';
const myURL = new URL(`https://example.org${pathname}${search}${hash}`);
要获取构造的网址字符串,则使用 href 属性访问器:
console.log(myURL.href);
URL 类#浏览器兼容的 URL 类,按照 WHATWG 网址标准实现。
解析网址的示例可以在标准本身中找到。
URL 类也在全局对象上可用。
按照浏览器的约定,URL 对象的所有属性都被实现为类原型上的获取器和设置器,而不是对象本身的数据属性。
因此,与旧版 urlObject 不同,在 URL 对象的任何属性上使用 delete 关键字(例如 delete myURL.protocol、delete myURL.pathname 等)没有任何作用,但仍会返回 true。
new URL(input[, base])#input <string> 要解析的绝对或相对的输入网址。
如果 input 是相对的,则需要 base。
如果 input 是绝对的,则忽略 base。
如果 input 不是字符串,则先转换成字符串。base <string> 如果 input 不是绝对的,则为要解析的基本网址。
如果 base 不是字符串,则先转换成字符串。通过相对于 base 解析 input 来创建新的 URL 对象。
如果 base 作为字符串传入,则其将被解析为等效于 new URL(base)。
const myURL = new URL('/foo', 'https://example.org/');
// https://example.org/foo
网址构造函数可作为全局对象的属性访问。 也可以从内置的 url 模块中导入:
import { URL } from 'url';
console.log(URL === globalThis.URL); // 打印 'true'.console.log(URL === require('url').URL); // 打印 'true'.
如果 input 或 base 不是有效的网址,则将抛出 TypeError。
注意,会将给定的值强制转换为字符串。
例如:
const myURL = new URL({ toString: () => 'https://example.org/' });
// https://example.org/
出现在 input 的主机名中的 Unicode 字符将使用 Punycode 算法自动转换为 ASCII。
const myURL = new URL('https://測試');
// https://xn--g6w251d/
只有在启用 ICU 的情况下编译 node 可执行文件时,此功能才可用。
如果不是,则域名将原封不动地传入。
如果事先不知道 input 是否是绝对的网址并且提供了 base,则建议验证 URL 对象的 origin 是否符合预期。
let myURL = new URL('http://Example.com/', 'https://example.org/');
// http://example.com/
myURL = new URL('https://Example.com/', 'https://example.org/');
// https://example.com/
myURL = new URL('foo://Example.com/', 'https://example.org/');
// foo://Example.com/
myURL = new URL('http:Example.com/', 'https://example.org/');
// http://example.com/
myURL = new URL('https:Example.com/', 'https://example.org/');
// https://example.org/Example.com/
myURL = new URL('foo:Example.com/', 'https://example.org/');
// foo:Example.com/
url.hash#获取和设置网址的片段部分。
const myURL = new URL('https://example.org/foo#bar');
console.log(myURL.hash);
// 打印 #bar
myURL.hash = 'baz';
console.log(myURL.href);
// 打印 https://example.org/foo#baz
分配给 hash 属性的值中包含的无效的网址字符会进行百分比编码。
选择要进行百分比编码的字符可能与 url.parse() 和 url.format() 方法产生的结果有所不同。
url.host#获取和设置网址的主机部分。
const myURL = new URL('https://example.org:81/foo');
console.log(myURL.host);
// 打印 example.org:81
myURL.host = 'example.com:82';
console.log(myURL.href);
// 打印 https://example.com:82/foo
分配给 host 属性的无效主机值将被忽略。
url.hostname#获取和设置网址的主机名部分。
url.host 和 url.hostname 之间的主要区别在于 url.hostname 不包括端口。
const myURL = new URL('https://example.org:81/foo');
console.log(myURL.hostname);
// 打印 example.org
// 设置主机名不会改变端口
myURL.hostname = 'example.com:82';
console.log(myURL.href);
// 打印 https://example.com:81/foo
// 使用 myURL.host 更改主机名和端口
myURL.host = 'example.org:82';
console.log(myURL.href);
// 打印 https://example.org:82/foo
分配给 hostname 属性的无效主机名值将被忽略。
url.href#获取和设置序列化的网址。
const myURL = new URL('https://example.org/foo');
console.log(myURL.href);
// 打印 https://example.org/foo
myURL.href = 'https://example.com/bar';
console.log(myURL.href);
// 打印 https://example.com/bar
获取 href 属性的值相当于调用 url.toString()。
将此属性的值设置为新值相当于使用 new URL(value) 创建新的 URL 对象。
URL 对象的每个属性都将被修改。
如果分配给 href 属性的值不是有效的网址,则将抛出 TypeError。
url.origin#获取网址的源的只读的序列化。
const myURL = new URL('https://example.org/foo/bar?baz');
console.log(myURL.origin);
// 打印 https://example.org
const idnURL = new URL('https://測試');
console.log(idnURL.origin);
// 打印 https://xn--g6w251d
console.log(idnURL.hostname);
// 打印 xn--g6w251d
url.password#获取和设置网址的密码部分。
const myURL = new URL('https://abc:xyz@example.com');
console.log(myURL.password);
// 打印 xyz
myURL.password = '123';
console.log(myURL.href);
// 打印 https://abc:123@example.com
分配给 password 属性的值中包含的无效的网址字符会进行百分比编码。
选择要进行百分比编码的字符可能与 url.parse() 和 url.format() 方法产生的结果有所不同。
url.pathname#获取和设置网址的路径部分。
const myURL = new URL('https://example.org/abc/xyz?123');
console.log(myURL.pathname);
// 打印 /abc/xyz
myURL.pathname = '/abcdef';
console.log(myURL.href);
// 打印 https://example.org/abcdef?123
分配给 pathname 属性的值中包含的无效的网址字符会进行百分比编码。
选择要进行百分比编码的字符可能与 url.parse() 和 url.format() 方法产生的结果有所不同。
url.port#获取和设置网址的端口部分。
端口值可以是数字,也可以是包含 0 到 65535(含)范围内的数字的字符串。
将值设置为给定 protocol 的 URL 对象的默认端口将导致 port 值成为空字符串 ('')。
端口值可以是空字符串,在这种情况下端口取决于协议/方案:
| 协议 | 端口 |
|---|---|
| "ftp" | 21 |
| "file" | |
| "http" | 80 |
| "https" | 443 |
| "ws" | 80 |
| "wss" | 443 |
为端口分配值后,该值将首先使用 .toString() 转换为字符串。
如果该字符串无效但以数字开头,则将前导数字分配给 port。
如果数字在上述范围之外,则将其忽略。
const myURL = new URL('https://example.org:8888');
console.log(myURL.port);
// 打印 8888
// 默认端口自动转换为空字符串
//(HTTPS 协议的默认端口是 443)
myURL.port = '443';
console.log(myURL.port);
// 打印空字符串
console.log(myURL.href);
// 打印 https://example.org/
myURL.port = 1234;
console.log(myURL.port);
// 打印 1234
console.log(myURL.href);
// 打印 https://example.org:1234/
// 完全无效的端口字符串被忽略
myURL.port = 'abcd';
console.log(myURL.port);
// 打印 1234
// 前导数字被视为端口号
myURL.port = '5678abcd';
console.log(myURL.port);
// 打印 5678
// 非整数被截断
myURL.port = 1234.5678;
console.log(myURL.port);
// 打印 1234
// 未用科学计数法表示的超出范围的数字将被忽略。
myURL.port = 1e10; // 10000000000,将按如下所述进行范围检查
console.log(myURL.port);
// 打印 1234
包含小数点的数字,例如浮点数或科学记数法中的数字,也不例外。 小数点前的前导数字将被设置为网址的端口,假设它们是有效的:
myURL.port = 4.567e21;
console.log(myURL.port);
// 打印 4(因为它是字符串 '4.567e21' 中的前导数字)
url.protocol#获取和设置网址的协议部分。
const myURL = new URL('https://example.org');
console.log(myURL.protocol);
// 打印 https:
myURL.protocol = 'ftp';
console.log(myURL.href);
// 打印 ftp://example.org/
分配给 protocol 属性的无效的网址协议值将被忽略。
WHATWG 网址标准认为少数网址协议方案在解析和序列化方式方面具有特殊性。
当使用这些特殊协议之一解析网址时,url.protocol 属性可能会更改为另一种特殊协议,但不能更改为非特殊协议,反之亦然。
例如,从 http 更改为 https 有效:
const u = new URL('http://example.org');
u.protocol = 'https';
console.log(u.href);
// https://example.org
但是,从 http 更改为假设的 fish 协议并不是因为新协议并不特殊。
const u = new URL('http://example.org');
u.protocol = 'fish';
console.log(u.href);
// http://example.org
同样,也不允许从非特殊协议更改为特殊协议:
const u = new URL('fish://example.org');
u.protocol = 'http';
console.log(u.href);
// fish://example.org
根据 WHATWG 网址标准,特殊协议方案有 ftp、file、http、https、ws 和 wss。
url.search#获取和设置网址的序列化的查询部分。
const myURL = new URL('https://example.org/abc?123');
console.log(myURL.search);
// 打印 ?123
myURL.search = 'abc=xyz';
console.log(myURL.href);
// 打印 https://example.org/abc?abc=xyz
出现在分配给 search 属性的值中的任何无效的网址字符都将进行百分比编码。
选择要进行百分比编码的字符可能与 url.parse() 和 url.format() 方法产生的结果有所不同。
url.searchParams#获取表示网址查询参数的 URLSearchParams 对象。
此属性是只读的,但它提供的 URLSearchParams 对象可用于更改网址实例; 要替换网址的整个查询参数,则使用 url.search 设置器。
有关详细信息,请参阅 URLSearchParams 文档。
当使用 .searchParams 修改 URL 时要小心,因为根据 WHATWG 规范,URLSearchParams 对象使用不同的规则来确定要对哪些字符进行百分比编码。
例如,URL 对象不会对 ASCII 波浪号 (~) 字符进行百分比编码,而 URLSearchParams 将始终对其进行编码:
const myUrl = new URL('https://example.org/abc?foo=~bar');
console.log(myUrl.search); // 打印 ?foo=~bar
// 通过 searchParams 修改网址...
myUrl.searchParams.sort();
console.log(myUrl.search); // 打印 ?foo=%7Ebar
url.username#获取和设置网址的用户名部分。
const myURL = new URL('https://abc:xyz@example.com');
console.log(myURL.username);
// 打印 abc
myURL.username = '123';
console.log(myURL.href);
// 打印 https://123:xyz@example.com/
出现在分配给 username 属性的值中的任何无效的网址字符都将进行百分比编码。
选择要进行百分比编码的字符可能与 url.parse() 和 url.format() 方法产生的结果有所不同。
url.toString()#URL 对象上的 toString() 方法返回序列化的网址。
返回值等同于 url.href 和 url.toJSON() 的值。
url.toJSON()#URL 对象上的 toJSON() 方法返回序列化的网址。
返回值等同于 url.href 和 url.toString() 的值。
当 URL 对象用 JSON.stringify() 序列化时,会自动调用此方法。
const myURLs = [
new URL('https://www.example.com'),
new URL('https://test.example.org'),
];
console.log(JSON.stringify(myURLs));
// 打印 ["https://www.example.com/","https://test.example.org/"]
URL.createObjectURL(blob)#创建表示给定的 <Blob> 对象并且可用于稍后检索 Blob 的 'blob:nodedata:...' 网址字符串。
const {
Blob,
resolveObjectURL,
} = require('buffer');
const blob = new Blob(['hello']);
const id = URL.createObjectURL(blob);
// 之后...
const otherBlob = resolveObjectURL(id);
console.log(otherBlob.size);
已注册的 <Blob> 存储的数据将保留在内存中,直到调用 URL.revokeObjectURL() 将其删除。
Blob 对象已在当前线程中注册。
如果使用工作线程,则在工作线程内注册的 Blob 对象将不能被其他工作线程或主线程使用。
URL.revokeObjectURL(id)#id <string> 先前调用 URL.createObjectURL() 返回的 'blob:nodedata:... 网址字符串。删除由给定标识符标识的已存储的 <Blob>。
URLSearchParams 类#URLSearchParams API 提供对 URL 查询的读写访问。
URLSearchParams 类也可以与以下四个构造函数之一单独使用。
URLSearchParams 类也在全局对象上可用。
WHATWG URLSearchParams 接口和 querystring 模块具有相似的用途,但 querystring 模块的用途更通用,因为它允许自定义的分隔符(& 和 =)。
换句话说,此 API 纯粹是为网址查询字符串而设计。
const myURL = new URL('https://example.org/?abc=123');
console.log(myURL.searchParams.get('abc'));
// 打印 123
myURL.searchParams.append('abc', 'xyz');
console.log(myURL.href);
// 打印 https://example.org/?abc=123&abc=xyz
myURL.searchParams.delete('abc');
myURL.searchParams.set('a', 'b');
console.log(myURL.href);
// 打印 https://example.org/?a=b
const newSearchParams = new URLSearchParams(myURL.searchParams);
// 以上相当于
// const newSearchParams = new URLSearchParams(myURL.search);
newSearchParams.append('a', 'c');
console.log(myURL.href);
// 打印 https://example.org/?a=b
console.log(newSearchParams.toString());
// 打印 a=b&a=c
// newSearchParams.toString() 是隐式调用的
myURL.search = newSearchParams;
console.log(myURL.href);
// 打印 https://example.org/?a=b&a=c
newSearchParams.delete('a');
console.log(myURL.href);
// 打印 https://example.org/?a=b&a=c
new URLSearchParams()#实例化新的空 URLSearchParams 对象。
new URLSearchParams(string)#string <string> 查询字符串将 string 解析为查询字符串,并使用它来实例化新的 URLSearchParams 对象。
前导 '?'(如果存在)将被忽略。
let params;
params = new URLSearchParams('user=abc&query=xyz');
console.log(params.get('user'));
// 打印 'abc'
console.log(params.toString());
// 打印 'user=abc&query=xyz'
params = new URLSearchParams('?user=abc&query=xyz');
console.log(params.toString());
// 打印 'user=abc&query=xyz'
new URLSearchParams(obj)#obj <Object> 表示键值对集合的对象使用查询哈希映射实例化新的 URLSearchParams 对象。
obj 的每个属性的键和值总是被强制转换为字符串。
与 querystring 模块不同,不允许以数组值的形式出现重复的键。
数组使用 array.toString() 字符串化,它简单地用逗号连接所有数组元素。
const params = new URLSearchParams({
user: 'abc',
query: ['first', 'second']
});
console.log(params.getAll('query'));
// 打印 [ 'first,second' ]
console.log(params.toString());
// 打印 'user=abc&query=first%2Csecond'
new URLSearchParams(iterable)#iterable <Iterable> 元素为键值对的可迭代对象以类似于 Map 的构造函数的方式使用可迭代映射实例化新的 URLSearchParams 对象。
iterable 可以是 Array 或任何可迭代对象。
这意味着 iterable 可以是另一个 URLSearchParams,在这种情况下,构造函数将简单地创建提供的 URLSearchParams 的克隆。
iterable 的元素是键值对,并且本身可以是任何可迭代对象。
允许重复的键。
let params;
// 使用数组
params = new URLSearchParams([
['user', 'abc'],
['query', 'first'],
['query', 'second'],
]);
console.log(params.toString());
// 打印 'user=abc&query=first&query=second'
// 使用 Map 对象
const map = new Map();
map.set('user', 'abc');
map.set('query', 'xyz');
params = new URLSearchParams(map);
console.log(params.toString());
// 打印 'user=abc&query=xyz'
// 使用生成器函数
function* getQueryPairs() {
yield ['user', 'abc'];
yield ['query', 'first'];
yield ['query', 'second'];
}
params = new URLSearchParams(getQueryPairs());
console.log(params.toString());
// 打印 'user=abc&query=first&query=second'
// 每个键值对必须恰好有两个元素
new URLSearchParams([
['user', 'abc', 'error'],
]);
// 抛出 TypeError [ERR_INVALID_TUPLE]:
// Each query pair must be an iterable [name, value] tuple
urlSearchParams.append(name, value)#将新的名称-值对追加到查询字符串。
urlSearchParams.delete(name)#name <string>删除名称为 name 的所有名称-值对。
urlSearchParams.entries()#在查询中的每个名称-值对上返回 ES6 Iterator。
迭代器的每一项都是 JavaScript Array。
Array 的第一项是 name,Array 的第二项是 value。