外观
URL Pattern API
简介
URL Pattern API 基于正则表达式和通配符,对 URL 进行匹配和解析。
它提供一个构造函数 URLPattern(),用于新建一个 URL 模式实例。
javascript
const pattern = new URLPattern(input);有了模式实例,就可以知道某个 URL 是否符合该模式。
javascript
const pattern = new URLPattern({ pathname: "/books" });
console.log(pattern.test("https://example.com/books")); // true上面示例中,模式实例是包含 /books 路径的 URL,实例方法 test() 用来检测指定网址是否符合该模式,结果为 true。
URL Pattern 支持多种协议,不仅是 HTTP 协议。
javascript
const pattern = new URLPattern("data\\:foo*");上面示例中,URL Pattern 新建了一个 Data 协议的模式。
构造函数 URLPattern()
基本用法
构造函数 URLPattern() 用于新建一个 URL 模式实例。
javascript
const pattern = new URLPattern(input);该构造函数的参数 input 是一个模式字符串或者模式对象。
javascript
new URLPattern("https://example.com/books/:id")
// {
// hasRegExpGroups: false,
// hash: "*",
// hostname: "example.com",
// password: "*",
// pathname: "/books/:id",
// port: "",
// protocol: "https",
// search: "*",
// username: "*",
// ...
// }上面示例中,参数 https://example.com/books/:id 就是一个模式字符串,执行后返回一个 URLPattern 实例对象,包含模式的各个组成部分。
参数 input 也可以写成一个对象,用属性指定模式 URL 的每个部分。也就是说,模式对象可以有以下属性。
- protocol
- username
- password
- hostname
- port
- pathname
- search
- hash
- baseURL
上面的示例,如果参数改成模式对象,就是下面这样。
javascript
new URLPattern({
protocol: 'https',
hostname: 'example.com',
pathname: '/books/:id',
})模式字符串或者模式对象之中,没有定义的部分,默认为 *,表示所有可能的字符,包括零字符的情况。
URLPattern() 正常情况下将返回一个 URLPattern 实例对象,但是遇到参数无效或语法不正确,则会报错。
javascript
new URLPattern(123) // 报错上面示例中,参数 123 不是一个有效的 URL 模式,就报错了。
需要注意的是,如果模式字符串为相对路径,那么 URLPattern() 还需要第二个参数,用来指定基准 URL。
javascript
new URLPattern(input, baseURL)上面代码中,第二个参数 baseURL 就是基准 URL。
javascript
new URLPattern('/books/:id') // 报错
new URLPattern('/books/:id', 'https://example.com') // 正确上面示例中,第一个参数 /books/:id 是一个相对路径,这时就需要第二个参数 https://example.com,用来指定基准 URL,否则报错。
但是,如果参数为模式对象,则可以只指定 URL 模式的某个部分。
javascript
new URLPattern({
pathname: '/books/:id'
}) // 正确上面示例中,参数是一个模式对象,那么参数允许只指定 URL 的部分模式。
模式对象里面,也可以指定基准 URL。
javascript
let pattern4 = new URLPattern({
pathname: "/books/:id",
baseURL: "https://example.com",
});基准 URL 必须是合法的 URL,不能包含模式。
注意,如果用了模式对象,就不能使用基准 URL 作为第二个参数,这样会报错。
javascript
new URLPattern({ pathname: "/foo/bar" }, "https://example.com") // 报错
new URLPattern({ pathname: "/foo/bar" }, "https://example.com/baz") // 报错上面示例中,同时使用了模式对象和第二个参数,结果就报错了。
URLpattern() 还可以加入配置对象参数,用于定制匹配行为。
javascript
new URLPattern(input, options)
new URLPattern(input, baseURL, options)上面代码中,参数 options 就是一个配置对象。
目前,这个配置对象 options 只有 ignoreCase 一个属性,如果设为 true,将不区分大小写,默认值为 false,表示区分大小写。
javascript
new URLPattern(input, {
ignoreCase: false // 默认值,区分大小写
})请看下面的例子。
javascript
const pattern = new URLPattern("https://example.com/2022/feb/*");
pattern.test("https://example.com/2022/feb/xc44rsz") // true
pattern.test("https://example.com/2022/Feb/xc44rsz") // false上面示例,默认匹配时,会区分 feb 和 Feb。
我们可以用 ignoreCase 将其关闭。
javascript
const pattern = new URLPattern(
"https://example.com/2022/feb/*",
{ ignoreCase: true, }
);
pattern.test("https://example.com/2022/feb/xc44rsz") // true
pattern.test("https://example.com/2022/Feb/xc44rsz") // true模式写法
模式字符串基本上采用正则表达式的写法,但是不是所有的正则语法都支持,比如先行断言和后行断言就不支持。
(1) 普通字符
如果都是普通字符,就表示原样匹配。
javascript
const p = new URLPattern('https://example.com/abc');上面代码就表示确切匹配路径 https://example.com/abc。
javascript
p.test('https://example.com') // false
p.test('https://example.com/a') //false
p.test('https://example.com/abc') // true
p.test('https://example.com/abcd') //false
p.test('https://example.com/abc/') //false
p.test('https://example.com/abc?123') //true上面示例中,URL 必须严格匹配路径 https://example.com/abc,即使尾部多一个斜杠都不行,但是加上查询字符串是可以的。
(2)?
量词字符 ? 表示前面的字符串,可以出现 0 次或 1 次,即该部分可选。
javascript
let pattern = new URLPattern({
protocol: "http{s}?",
});上面示例中,{s}? 表示字符组 s 可以出现 0 次或 1 次。
? 不包括路径的分隔符 /。
javascript
const pattern = new URLPattern("/books/:id?", "https://example.com");
pattern.test("https://example.com/books/123") // true
pattern.test("https://example.com/books") // true
pattern.test("https://example.com/books/") // false
pattern.test("https://example.com/books/123/456") // false
pattern.test("https://example.com/books/123/456/789") // false
pattern.test("https://example.com/books/123/456/") // false上面示例中,? 不能匹配网址结尾的斜杠。
如果一定要匹配,可以把结尾的斜杠放在 {} 里面。
javascript
const pattern = new URLPattern({ pathname: "/product{/}?" });
pattern.test({ pathname: "/product" }) // true
pattern.test({ pathname: "/product/" }) // true上面示例中,不管网址有没有结尾的斜杠,{/}? 都会成功匹配。
(3)+
量词字符 + 表示前面的字符串出现 1 次或多次。
javascript
const pattern = new URLPattern({
pathname: "/books/(\\d+)",
})上面示例中,\\d+ 表示 1 个或多个数字,其中的 \d 是一个内置的字符类,表示 0-9 的数字,因为放在双引号里面,所以反斜杠前面还要再加一个反斜杠进行转义。
+ 可以包括 / 分隔的路径的多个部分,但不包括路径结尾的斜杠。
javascript
const pattern = new URLPattern("/books/:id+", "https://example.com");
pattern.test("https://example.com/books/123") // true
pattern.test("https://example.com/books") // false
pattern.test("https://example.com/books/") // false
pattern.test("https://example.com/books/123/456") // true
pattern.test("https://example.com/books/123/456/789") // true
pattern.test("https://example.com/books/123/456/") // false(4)*
量词字符 * 表示出现零次或多次。
javascript
const pattern = new URLPattern('https://example.com/{abc}*');
pattern.test('https://example.com') // true
pattern.test('https://example.com/') // true
pattern.test('https://example.com/abc') // true
pattern.test('https://example.com/abc/') // false
pattern.test('https://example.com/ab') // false
pattern.test('https://example.com/abcabc') // true
pattern.test('https://example.com/abc/abc/abc') // false上面示例中,{abc}* 表示 abc 出现零次或多次,也不包括路径分隔符 /。
如果 * 前面没有任何字符,就表示所有字符,包括零字符的情况,也包括分隔符 /。
javascript
let pattern = new URLPattern({
search: "*",
hash: "*",
});上面示例中,* 表示匹配所有字符,包括零字符。
下面是另一个例子。
javascript
const pattern = new URLPattern("/*.png", "https://example.com");
pattern.test("https://example.com/image.png") // true
pattern.test("https://example.com/image.png/123") // false
pattern.test("https://example.com/folder/image.png") // true
pattern.test("https://example.com/.png") // true* 匹配的部分可以从对应部分的数字属性上获取。
javascript
const pattern = new URLPattern({
hostname: "example.com",
pathname: "/foo/*"
});
const result = pattern.exec("/foo/bar", "https://example.com/baz");
result.pathname.input // '/foo/bar'
result.pathname.groups[0] // 'bar'上面示例中,* 的匹配结果可以从 pathname.groups[0] 获取。
javascript
const pattern = new URLPattern({ hostname: "*.example.com" });
const result = pattern.exec({ hostname: "cdn.example.com" });
result.hostname.groups[0] // 'cdn'
result.hostname.input // 'cdn.example.com'上面示例中,* 的匹配结果可以从 hostname.groups[0] 获取。
(5){}
特殊字符 {} 用来定义量词 ?、+、+ 的生效范围。
如果 {} 后面没有量词,那就跟没有使用的效果一样。
javascript
const pattern = new URLPattern('https://example.com/{abc}');
pattern.test('https://example.com/') // false
pattern.test('https://example.com/abc') // true(6)()
特殊字符 () 用来定义一个组匹配,匹配结果可以按照出现顺序的编号,从 pathname.groups 对象上获取。
javascript
const pattern = new URLPattern("/books/(\\d+)", "https://example.com");
pattern.exec("https://example.com/books/123").pathname.groups
// { '0': '123' }上面示例中,(\\d+) 是一个组匹配,因为它是第一个组匹配,所以匹配结果放在 pathname.groups 的属性 0。
(7)|
特殊字符 | 表示左右两侧的字符,都可以出现,即表示逻辑 OR。
javascript
let pattern = new URLPattern({
port: "(80|443)",
});上面示例中,(80|443) 表示 80 或者 443 都可以。
(8):
特殊字符 : 用来定义一个具名组匹配,后面跟着变量名。
javascript
let pattern = new URLPattern({
pathname: "/:path",
});上面示例中,/:path 表示斜杠后面的部分,都被捕捉放入变量 path,可以从匹配结果的 pathname.groups 上的对应属性获取。
javascript
const pattern = new URLPattern({ pathname: "/books/:id" });
pattern.exec("https://example.com/books/123").pathname.groups
// { id: '123' }上面示例中,pathname.groups 返回一个对象,该对象的属性就是所有捕捉成功的组变量,上例是 id。
下面是另一个例子。
javascript
const pattern = new URLPattern({ pathname: "/:product/:user/:action" });
const result = pattern.exec({ pathname: "/store/wanderview/view" });
result.pathname.groups.product // 'store'
result.pathname.groups.user // 'wanderview'
result.pathname.groups.action // 'view'
result.pathname.input // '/store/wanderview/view'上面示例中,:product、:user、:action 的匹配结果,都可以从 pathname.groups 的对应属性上获取。
组匹配可以放在模式的前面。
javascript
const pattern = new URLPattern(
"/books/:id(\\d+)",
"https://example.com"
);上面示例中,组匹配 :id 后面跟着模型定义 \\d+,模式需要放在括号里面。
(9) 特殊字符转义
如果要将特殊字符当作普通字符使用,必须在其前面加入双重反斜杠进行转义。
javascript
let pattern1 = new URLPattern({
pathname: "/a:b",
});
let pattern2 = new URLPattern({
pathname: "/a\\:b",
});上面示例中,a:b 表示路径以字符 a 开头,后面的部分都放入变量 b。而 a\\:b 表示路径本身就是 a:b 就是。
实例属性
URLPattern 实例的属性对应 URLPattern() 模式对象参数的各个部分。
javascript
const pattern = new URLPattern({
hostname: "{*.}?example.com",
});
pattern.hostname // '{*.}?example.com'
pattern.protocol // '*'
pattern.username // '*'
pattern.password // '*'
pattern.port // ""
pattern.pathname // '*'
pattern.search // '*'
pattern.hash // '*'上面示例中,pattern 是一个实例对象,它的属性与 URLPattern() 的参数对象的属性一致。
注意,search 不包括开头的 ?,hash 不包括开头的 #,但是 pathname 包括开头的 /。
下面是另一个例子。
javascript
const pattern = new URLPattern("https://cdn-*.example.com/*.jpg");
pattern.protocol // 'https'
pattern.hostname // 'cdn-*.example.com'
pattern.pathname // '/*.jpg'
pattern.username // ''
pattern.password // ''
pattern.search // ''
pattern.hash // ''实例方法
exec()
实例的 exec() 方法,把模式用于解析参数网址,返回匹配结果。
exec() 方法的参数与 new URLPattern() 是一致的。它可以是一个 URL 字符串。
javascript
pattern.exec("https://store.example.com/books/123");如果第一个参数是相对 URL,那么需要基准 URL,作为第二个参数。
javascript
pattern.exec("/foo/bar", "https://example.com/baz");exec() 方法的参数,也可以是一个对象。
javascript
pattern.exec({
protocol: "https",
hostname: "store.example.com",
pathname: "/books/123",
});如果匹配成功,它返回一个包括匹配结果的对象。如果匹配失败,返回 null。
javascript
const pattern = new URLPattern("http{s}?://*.example.com/books/:id");
pattern.exec("https://example.com/books/123") // null上面示例中,匹配失败返回 null。
匹配成功返回的对象,有一个 inputs 属性,包含传入 pattern.exec() 的参数数组。其他属性的值也是一个对象,该对象的 input 属性对应传入值,groups 属性包含各个组匹配。
javascript
const pattern = new URLPattern("http{s}?://*.example.com/books/:id");
let match = pattern.exec("https://store.example.com/books/123");
match.inputs // ['https://store.example.com/books/123']
match.protocol // { input: "https", groups: {} }
match.username // { input: "", groups: {} }
match.password // { input: "", groups: {} }
match.hostname // { input: "store.example.com", groups: { "0": "store" } }
match.port // { input: "", groups: {} }
match.pathname // { input: "/books/123", groups: { "id": "123" } }
match.search // { input: "", groups: {} }
match.hash // { input: "", groups: {} }test()
实例的 test() 方法,用来检测参数网址是否符合当前模式。
它的参数跟 URLPattern() 是一样的,可以是模式字符串,也可以是模式对象。
javascript
const pattern = new URLPattern({
hostname: "example.com",
pathname: "/foo/*"
});
pattern.test({
pathname: "/foo/bar",
baseURL: "https://example.com/baz",
}) // true
pattern.test("/foo/bar", "https://example.com/baz") // true正常情况下,它返回一个布尔值。但是,如果语法不合法,它也会抛错。
javascript
pattern.test({ pathname: "/foo/bar" }, "https://example.com/baz") // 报错