URLPattern API 實戰:瀏覽器原生路由匹配與模式解析

技术架构(更新於 2026年6月16日)

URLPattern API 概述

URLPattern 是瀏覽器原生提供的 URL 模式匹配介面,靈感來自 Express 路由語法,但功能更強大——支援協定、主機、埠、路徑、查詢參數和雜湊的獨立模式匹配。

const pattern = new URLPattern({ pathname: '/api/users/:id' });
const result = pattern.exec('https://example.com/api/users/42');
console.log(result.pathname.groups.id);

模式語法詳解

基礎語法:通配符與命名組

語法 含義 範例 匹配
* 通配符,匹配任意字串 /api/* /api/anything
:name 命名捕獲組 /users/:id /users/42{id: "42"}
:name+ 命名組匹配多段路徑 /files/:path+ /files/a/b/c{path: "a/b/c"}
(.*) 正則分組 /old/(.*) /old/page{0: "page"}

正則約束命名組

const pattern = new URLPattern({
  pathname: '/products/:id(\\d+)'
});

pattern.test('https://shop.com/products/123');
pattern.test('https://shop.com/products/abc');

完整 URL 各元件模式

const apiPattern = new URLPattern({
  protocol: 'https',
  hostname: ':sub.example.com',
  pathname: '/v:version/:resource/:id?',
  search: 'sort=:sort&*'
});

const match = apiPattern.exec({
  protocol: 'https',
  hostname: 'api.example.com',
  pathname: '/v2/users/42',
  search: 'sort=name&page=1'
});

if (match) {
  console.log(match.hostname.groups.sub);
  console.log(match.pathname.groups.version);
  console.log(match.pathname.groups.resource);
  console.log(match.pathname.groups.id);
  console.log(match.search.groups.sort);
}

Service Worker 路由攔截

URLPattern 與 Service Worker 的結合是瀏覽器原生路由層的核心場景。

基於 URLPattern 的 SW 路由分發

self.addEventListener('fetch', (event) => {
  const routes = [
    { pattern: new URLPattern({ pathname: '/api/*' }), handler: handleApi },
    { pattern: new URLPattern({ pathname: '/static/*' }), handler: handleStatic },
    { pattern: new URLPattern({ pathname: '/pages/:slug' }), handler: handlePage },
  ];

  for (const { pattern, handler } of routes) {
    const result = pattern.exec(event.request.url);
    if (result) {
      event.respondWith(handler(event, result));
      return;
    }
  }
});

async function handleApi(event, match) {
  const cache = await caches.open('api-cache');
  const cached = await cache.match(event.request);
  if (cached) return cached;

  const response = await fetch(event.request);
  await cache.put(event.request, response.clone());
  return response;
}

使用 Chrome Route API(實驗性)

if ('routes' in self.registration) {
  self.registration.routes.add(
    new URLPattern({ pathname: '/api/*' }),
    new CacheFirstStrategy({ cacheName: 'api-cache' })
  );
}

客戶端路由匹配

SPA 路由器實作

class Router {
  constructor() {
    this.routes = [];
    window.addEventListener('popstate', () => this.resolve());
  }

  add(pattern, handler) {
    this.routes.push({
      pattern: new URLPattern({ pathname: pattern }),
      handler
    });
    return this;
  }

  resolve(pathname = location.pathname) {
    for (const { pattern, handler } of this.routes) {
      const result = pattern.exec({ pathname });
      if (result) {
        handler(result.pathname.groups);
        return;
      }
    }
    console.warn(`No route matched: ${pathname}`);
  }

  navigate(path) {
    history.pushState(null, '', path);
    this.resolve(path);
  }
}

const router = new Router();
router
  .add('/dashboard', (params) => renderDashboard())
  .add('/users/:id', (params) => renderUser(params.id))
  .add('/posts/:slug/comments/:commentId?', (params) => renderComment(params))
  .add('/*', () => renderNotFound());

router.resolve();

模式匹配 vs 傳統方案對比

特性 URLPattern API RegExp path-to-regexp Express
瀏覽器原生
URL 元件拆分 ✅ 協定/主機/路徑/查詢 部分
命名捕獲組 ❌ (ES2025前)
正則約束 :id(\\d+)
型別安全結果 ✅ groups 物件
效能 原生 C++ 實作 JS 引擎最佳化 JS 解析 JS 解析

實用模式集合

const patterns = {
  apiV1: new URLPattern({ pathname: '/api/v1/:resource/:id?' }),
  apiV2: new URLPattern({ pathname: '/api/v2/:resource/:id?' }),
  userAssets: new URLPattern({ pathname: '/users/:userId/:type(img|doc|pdf)/*' }),
  localePage: new URLPattern({ pathname: '/:locale(zh-TW|en|ja)/:page*' }),
  searchWithFilter: new URLPattern({ pathname: '/search', search: 'q=:query&filter=:filter?' }),
};

function matchRoute(url) {
  for (const [name, pattern] of Object.entries(patterns)) {
    const result = pattern.exec(url);
    if (result) return { name, groups: result.pathname.groups, search: result.search.groups };
  }
  return null;
}

瀏覽器相容與 Polyfill

瀏覽器 支援狀態 備註
Chrome 95+ 完整支援
Edge 95+ 完整支援
Firefox ⚠️ 需 polyfill
Safari 17+ 完整支援
npm install urlpattern-polyfill
import { URLPattern } from 'urlpattern-polyfill';
if (!globalThis.URLPattern) {
  globalThis.URLPattern = URLPattern;
}

最佳實踐總結

  1. 優先使用命名組而非索引存取,提升可讀性與可維護性
  2. 對動態段施加正則約束,避免無效匹配進入處理邏輯
  3. SW 路由按優先級排列,API 路由優先於通配兜底
  4. 利用 URL 元件獨立匹配,協定與主機模式可鎖定安全來源
  5. 漸進增強:偵測 API 可用性,不可用時回退至 RegExp 方案

URLPattern API 將路由匹配從框架依賴中解放出來,成為瀏覽器基礎設施的一部分。結合 Service Worker,它為離線優先架構提供了原生路由層支撐。

本站提供瀏覽器本地工具,免註冊即可試用 →

#URLPattern#路由匹配#Service Worker#Web API#模式匹配