内置的 URL 类提供了一个方便的接口来创建和解析 URL。
没有网络方法需要确切的 URL
对象,字符串就足够了。所以从技术上讲,我们不必使用 URL
。但有时它确实很有帮助。
创建 URL
创建新的 URL
对象的语法
new URL(url, [base])
url
– 完整的 URL 或仅路径(如果设置了 base,请参见下文),base
– 可选的基础 URL:如果设置了该参数并且url
参数只有路径,则 URL 是相对于base
生成的。
例如
let url = new URL('https://javascript.js.cn/profile/admin');
这两个 URL 相同
let url1 = new URL('https://javascript.js.cn/profile/admin');
let url2 = new URL('/profile/admin', 'https://javascript.js.cn');
alert(url1); // https://javascript.js.cn/profile/admin
alert(url2); // https://javascript.js.cn/profile/admin
我们可以轻松地基于相对于现有 URL 的路径创建新的 URL
let url = new URL('https://javascript.js.cn/profile/admin');
let newUrl = new URL('tester', url);
alert(newUrl); // https://javascript.js.cn/profile/tester
URL
对象允许我们立即访问其组件,因此它是解析 URL 的一种好方法,例如:
let url = new URL('https://javascript.js.cn/url');
alert(url.protocol); // https:
alert(url.host); // javascript.info
alert(url.pathname); // /url
以下是 URL 组件的速查表
href
是完整的 URL,与url.toString()
相同protocol
以冒号字符:
结尾search
– 一串参数,以问号?
开头hash
以井号#
开头- 如果存在 HTTP 身份验证,还可能存在
user
和password
属性:http://login:[email protected]
(上面没有画出,很少使用)。
URL
对象传递给网络(以及大多数其他)方法,而不是字符串我们可以在 fetch
或 XMLHttpRequest
中使用 URL
对象,几乎在所有需要 URL 字符串的地方都可以使用。
通常,URL
对象可以传递给任何方法,而不是字符串,因为大多数方法将执行字符串转换,将 URL
对象转换为包含完整 URL 的字符串。
SearchParams “?…”
假设我们想要创建一个具有给定搜索参数的 URL,例如 https://google.com/search?query=JavaScript
。
我们可以在 URL 字符串中提供它们
new URL('https://google.com/search?query=JavaScript')
…但是如果参数包含空格、非拉丁字母等,则需要对其进行编码(下面将详细介绍)。
因此,有一个 URL 属性用于此:url.searchParams
,一个类型为 URLSearchParams 的对象。
它为搜索参数提供了方便的方法
append(name, value)
– 按name
添加参数,delete(name)
– 按name
删除参数,get(name)
– 按name
获取参数,getAll(name)
– 获取具有相同name
的所有参数(这是可能的,例如?user=John&user=Pete
),has(name)
– 检查参数是否存在于name
中,set(name, value)
– 设置/替换参数,sort()
– 按名称对参数进行排序,很少需要,- …它也是可迭代的,类似于
Map
。
包含空格和标点符号的参数示例
let url = new URL('https://google.com/search');
url.searchParams.set('q', 'test me!'); // added parameter with a space and !
alert(url); // https://google.com/search?q=test+me%21
url.searchParams.set('tbs', 'qdr:y'); // added parameter with a colon :
// parameters are automatically encoded
alert(url); // https://google.com/search?q=test+me%21&tbs=qdr%3Ay
// iterate over search parameters (decoded)
for(let [name, value] of url.searchParams) {
alert(`${name}=${value}`); // q=test me!, then tbs=qdr:y
}
编码
有一个标准的 RFC3986 定义了哪些字符允许在 URL 中使用,哪些字符不允许。
不允许使用的字符必须进行编码,例如非拉丁字母和空格 - 替换为它们的 UTF-8 代码,并在前面加上 %
,例如 %20
(空格可以用 +
编码,出于历史原因,但这是一种例外情况)。
好消息是 URL
对象会自动处理所有这些。我们只需提供所有未编码的参数,然后将 URL
转换为字符串。
// using some cyrillic characters for this example
let url = new URL('https://ru.wikipedia.org/wiki/Тест');
url.searchParams.set('key', 'ъ');
alert(url); //https://ru.wikipedia.org/wiki/%D0%A2%D0%B5%D1%81%D1%82?key=%D1%8A
如您所见,url 路径中的 Тест
和参数中的 ъ
都被编码了。
URL 变长了,因为每个西里尔字母在 UTF-8 中用两个字节表示,所以有两个 %..
实体。
编码字符串
在 URL
对象出现之前,人们使用字符串来表示 URL。
现在,URL
对象通常更方便,但字符串仍然可以使用。在许多情况下,使用字符串可以使代码更短。
但是,如果我们使用字符串,我们需要手动编码/解码特殊字符。
为此,有内置函数
- encodeURI - 将整个 URL 编码。
- decodeURI - 将其解码回来。
- encodeURIComponent - 编码 URL 组件,例如搜索参数、哈希或路径名。
- decodeURIComponent - 将其解码回来。
一个自然的问题是:“encodeURIComponent
和 encodeURI
之间有什么区别?我们什么时候应该使用哪一个?”
如果我们看一下上面的图片中分成组件的 URL,就很容易理解了。
https://site.com:8080/path/page?p1=v1&p2=v2#hash
如我们所见,:
、?
、=
、&
、#
等字符在 URL 中是允许的。
另一方面,如果我们看一下单个 URL 组件,例如搜索参数,这些字符必须进行编码,以避免破坏格式。
encodeURI
只编码在 URL 中完全禁止的字符。encodeURIComponent
编码相同的字符,此外还编码#
、$
、&
、+
、,
、/
、:
、;
、=
、?
和@
。
因此,对于整个 URL,我们可以使用 encodeURI
// using cyrillic characters in url path
let url = encodeURI('http://site.com/привет');
alert(url); // http://site.com/%D0%BF%D1%80%D0%B8%D0%B2%D0%B5%D1%82
而对于 URL 参数,我们应该使用 encodeURIComponent
let music = encodeURIComponent('Rock&Roll');
let url = `https://google.com/search?q=${music}`;
alert(url); // https://google.com/search?q=Rock%26Roll
将其与 encodeURI
进行比较
let music = encodeURI('Rock&Roll');
let url = `https://google.com/search?q=${music}`;
alert(url); // https://google.com/search?q=Rock&Roll
正如我们所见,encodeURI
不会对 &
进行编码,因为这在整个 URL 中是一个合法的字符。
但我们应该在搜索参数内部对 &
进行编码,否则,我们会得到 q=Rock&Roll
- 这实际上是 q=Rock
加上一些模糊的参数 Roll
。并非预期结果。
因此,我们应该只对每个搜索参数使用 encodeURIComponent
,以便将其正确地插入到 URL 字符串中。最安全的做法是对名称和值都进行编码,除非我们绝对确定它只包含允许的字符。
URL
相比的编码差异类 URL 和 URLSearchParams 基于最新的 URI 规范:RFC3986,而 encode*
函数基于过时的版本 RFC2396。
有一些区别,例如 IPv6 地址的编码方式不同。
// valid url with IPv6 address
let url = 'http://[2607:f8b0:4005:802::1007]/';
alert(encodeURI(url)); // http://%5B2607:f8b0:4005:802::1007%5D/
alert(new URL(url)); // http://[2607:f8b0:4005:802::1007]/
正如我们所见,encodeURI
替换了方括号 [...]
,这是不正确的,原因是:在 RFC2396(1998 年 8 月)发布时,IPv6 URL 还不存在。
这种情况很少见,encode*
函数在大多数情况下都能正常工作。
评论
<code>
标签,对于多行代码,请将其包装在<pre>
标签中,对于超过 10 行的代码,请使用沙盒(plnkr,jsbin,codepen…)。