URLPattern · 浏览器内建的 URL matcher
匹配引擎页手写了一台 path → handler 引擎:按 / 切段、逐段对齐、提取 :param。URLPattern 是浏览器把这台引擎标准化、内建的原生 API——而且能力远超手工实现的版本。两点不同最关键:一是匹配范围从「只切
pathname 一段」扩到整条 URL 的每个组成部分(protocol / hostname / port / pathname / search / hash);二是语法从「:param / * 两种」扩到带正则约束的命名组 :id(\d+)、可选分组 {/:slug}?、可重复段 :rest*、枚举
(en|zh)。
本页是真的在调用你浏览器里的 window.URLPattern。下面两个 demo 都即时构造一个 new URLPattern(...)、用 test() 判命中、用 exec() 取出每个命名组,改 pattern 或改输入都当场重算。先在 pathname 这一段上看清语法,再把视野放大到整条 URL。
1 · 语法探索器 · 在 pathname 上看清每种 segment
2 · 语法速查
| 语法 | 含义 | 例 |
|---|---|---|
:name |
命名组,吃一段(默认不跨 /) |
/users/:id 配 /users/42 → { id: "42" } |
:name(regex) |
给这一段加正则约束 | :id(\d+) 只配数字;/users/abc 直接 miss |
* |
通配,吃掉剩余;是匿名组,组名为字符串 "0" |
/files/* 配 /files/a/b.png |
:name* · :name+ |
可重复段(0+ / 1+),把跨段的剩余收进命名组 | /files/:rest* → { rest: "a/b.png" } |
{…}? |
可选分组,默认时该组值为 undefined |
/posts{/:slug}? 同时配 /posts 与 /posts/x |
(a|b) |
枚举(其实就是正则约束) | /:lang(en|zh)/about 只接受 en / zh |
这套语法来自 path-to-regexp 一脉,React Router / Express 用户会很眼熟——区别是 URLPattern 把它写进了 Web 标准。
3 · 放大视野 · 不止 pathname,整条 URL 都能写 pattern
手工实现的 matcher 只认 pathname 那一段。URLPattern 的 pattern 是个多组件对象——protocol / hostname / port / pathname / search / hash 各写各的、全部命中才算命中,任一组件没写则默认
*(匹配任意)。下面固定 protocol: "https",你可改 hostname 与 pathname 两条 pattern,看同一批 URL 哪些过、卡在哪个组件上,以及连子域都能作为命名组提取出来。
4 · 真实用法
test() 判命中、exec() 取每个组件的命名组。
// 浏览器内建的 URL matcher —— 不必再手搓 segsOf / matchPattern
const p = new URLPattern({ pathname: '/users/:id(\\d+)' });
p.test({ pathname: '/users/42' }); // → true
p.test({ pathname: '/users/abc' }); // → false (:id 限定 \\d+)
const m = p.exec({ pathname: '/users/42' });
m.pathname.groups; // → { id: '42' }
// 不止 pathname: 整条 URL 的每个组件都能写 pattern, 全部命中才算命中
const api = new URLPattern({
protocol: 'https',
hostname: ':sub.example.com', // 连子域都能作为命名组提取
pathname: '/api/:version/users/:id(\\d+)',
});
api.exec('https://app.example.com/api/v2/users/42');
// → { hostname: { groups: { sub: 'app' } },
// pathname: { groups: { version: 'v2', id: '42' } }, ... }
// 也能直接用一整条 URL 字符串构造 (没写的组件默认 * 通配)
new URLPattern('https://*.example.com/api/*');
5 · 它和手工实现的 matcher 差在哪
| 这件事 | 手工实现的 matcher(匹配引擎) | URLPattern |
|---|---|---|
| 匹配范围 | 只切 pathname 一段 | 整条 URL 七个组件,全部命中才算命中 |
| 命名参数 | :id 吃一段 |
:id 一样,但可加正则约束 :id(\d+) |
| 通配 | * 吃剩余 |
* / :rest* / :rest+,还能带前后缀 |
| 可选段 | 不支持——得写两条路由 | {/:id}? 内建可选,一条搞定 |
| 提取结果 | 自己拼 params 对象 | exec() 给每个组件的 .groups |
| 来源 | 你维护的几十行代码 | 浏览器内建 / Web 标准(Node · Deno · Workers 也有) |
一句话:匹配引擎页讲的是「这台引擎内部怎么跑」,本页讲的是「浏览器已经把这台引擎做好了,而且更全」。
几处容易踩的。 默认不跨 /::name 只吃一段,要跨段收剩余得用 * 或 :name*。匿名组叫 "0":* 的捕获结果在 groups["0"],不是某个名字。JS 字符串里 \ 要转义:在源码里写 :id(\\d+) 才得到正则 \d+(本页输入框里直接写一个 \ 即可,因为读的是 input.value)。是 full match:pattern 默认匹配整个组件,不是子串搜索;没写的组件默认 *,容易「以为限制了其实没限制」。
6 · 相关页
- 本系列 · 路由匹配引擎——先看手写版怎么按
/切段、逐段对齐、提取:param,以及「顺序即优先级」「specificity 排序」「radix tree」三条路——本页是它的标准化、整条 URL 版。 - 本系列 · Navigation API——同属「为路由重做的现代浏览器原生接口」:Navigation API 接住导航事件,URLPattern 负责匹配——两者常一起搭出新一代 client router。
- URL Anatomy · 一条网址怎么拆开——URLPattern 的多组件(protocol / hostname / port / pathname / search / hash)正好对应一条 URL 的各块,那个系列逐段拆开讲。
- MDN · URLPattern API——构造器(字符串 / URLPatternInit 两种)、test() / exec()、各组件语法与浏览器兼容性的权威说明。
- WHATWG · URLPattern Standard——规范本体:pattern 如何解析成各组件、命名组 / 正则组 / 通配的精确语义。