URLPattern 提供路徑至網路平台

一種將常見模式比對用途標準化的做法。

路由是每個網頁應用程式的重要元素。在本質上,路由會擷取網址,並套用某些模式比對或其他應用程式專屬邏輯,然後通常會根據結果顯示網頁內容。您可以透過多種方式實作路由:有時是執行在伺服器上的程式碼,將路徑對應至磁碟上的檔案;有時則是單頁應用程式中的邏輯,會等待目前位置的變更,並建立相應的 DOM 片段進行顯示。

雖然沒有明確的標準,但網頁開發人員傾向使用通用的語法來表示網址路徑模式,這些模式與 regular expressions 有許多共同之處,但也加入了一些特定領域的內容,例如用於比對路徑區段的符記。ExpressRuby on Rails 等熱門伺服器端架構會使用這種語法 (或是非常接近此語法),而 JavaScript 開發人員可以使用 path-to-regexpregexpparam 等模組,將該邏輯加入自己的程式碼。

URLPattern 是網頁平台的附加元件,可在這些架構建立的基礎上建構。其目標是將路由模式語法標準化,包括支援萬用字元、命名符記群組、規則運算式群組和群組修飾符。使用這個語法建立的 URLPattern 執行個體可以執行常見的轉送工作,例如比對完整網址或網址 pathname,以及傳回憑證和群組相符項目的相關資訊。

直接在網頁平台中提供網址比對功能的另一個好處是,您可以將通用語法與其他 API共用,這些 API 也需要比對網址。

瀏覽器支援和 polyfill

根據預設,Chrome 和 Edge 95 以上版本會啟用 URLPattern

urlpattern-polyfill 程式庫可讓您在不支援內建支援的瀏覽器或環境 (例如 Node) 中使用 URLPattern 介面。如果您使用 polyfill,請務必使用功能偵測功能,確保您只在目前環境缺乏支援時才載入 polyfill。否則,您將失去 URLPattern 的一項重要優點:支援環境不必下載及剖析額外程式碼,才能使用 URLPattern

if (!(globalThis && 'URLPattern' in globalThis)) {
  // URLPattern is not available, so the polyfill is needed.
}

語法相容性

URLPattern」的指導理念是避免全新發明。如果您已經熟悉 Express 或 Ruby on Rails 中使用的轉送語法,就應該先學習新知識。不過,由於常見路徑設定程式庫的語法之間存在些微差異,因此必須選擇某種語法做為基礎語法,URLPattern 的設計人員決定使用 path-to-regexp 的模式語法 (但不是其 API 介面) 做為起點。

我們在與 path-to-regexp 的現任維護者密切討論後,做出了這項決定。

如要熟悉支援的語法核心,請參閱 path-to-regexp說明文件。您可以閱讀說明文件,瞭解在 GitHub 上發布的 MDN 說明文件。

其他功能

URLPattern 的語法是 path-to-regexp 支援的超集,因為 URLPattern 支援轉送程式庫中不常見的功能:比對來源,包括主機名稱中的萬用字元。大多數其他路徑設定程式庫只會處理pathname,偶爾處理網址的搜尋雜湊部分。而且不必檢查網址的來源部分,因為這類網址僅適用於獨立網頁應用程式內的相同來源轉送。

考量來源後,您就能使用其他用途,例如在服務工作者fetch 事件處理常式中,路由跨來源要求。如果您只轉送相同來源的網址,可以有效忽略這項額外功能,並像其他程式庫一樣使用 URLPattern

範例

建構模式

如要建立 URLPattern,請將其建構函式傳遞給字串或物件,其中屬性包含要比對的模式相關資訊。

傳送物件可讓您更明確控管比對每個網址元件的模式。最詳盡的是

const p = new URLPattern({
  protocol: 'https',
  username: '',
  password: '',
  hostname: 'example.com',
  port: '',
  pathname: '/foo/:image.jpg',
  search: '*',
  hash: '*',
});

只有在未設定網址的對應部分時,系統才會比對屬性的空白字串。萬用字元 * 會比對網址指定部分的任何值。

建構函式提供多種快速鍵,可簡化使用方式。完全省略 searchhash 或任何其他屬性,等同於將這些屬性設為 '*' 萬用字元。上面的範例可以簡化為

const p = new URLPattern({
  protocol: 'https',
  username: '',
  password: '',
  hostname: 'example.com',
  port: '',
  pathname: '/foo/:image.jpg',
});

您也可以使用其他捷徑,在單一屬性 baseURL 中提供所有來源資訊,進而

const p = new URLPattern({
  pathname: '/foo/:image.jpg',
  baseURL: 'https://example.com',
});

所有這些範例都假設您的用途涉及比對來源。如果您只想比對網址的其他部分,而非來源 (許多「傳統」單來源路由情況即是如此),則可以完全省略來源資訊,只提供 pathnamesearchhash 屬性的組合。如同先前所述,系統會將省略的屬性視為設為 * 萬用字元模式。

const p = new URLPattern({pathname: '/foo/:image.jpg'});

您可以提供一或兩個字串,做為傳遞物件至建構函式的替代做法。如果提供一個字串,則這應該代表完整的網址模式,包括用來比對來源的模式資訊。如果您提供兩個字串,系統會將第二個字串用作 baseURL,而第一個字串則會視為相對於該基底。

無論是否提供一個字串,URLPattern 建構函式都會剖析完整網址模式,將其拆分為網址元件,然後將較大模式的各部分對應至對應的元件。也就是說,在幕後,每個使用字串建立的 URLPattern 最終都會以與使用物件建立的等效 URLPattern 相同方式呈現。字串建構函式只是捷徑,適合偏好較精簡介面的使用者。

const p = new URLPattern('https://example.com/foo/:image.jpg?*#*');

使用字串建立 URLPattern 時,請留意以下幾點。

使用物件建構 URLPattern 時,如果省略屬性,就等同於為該屬性提供 * 萬用字元。剖析完整網址字串模式時,如果其中一個網址元件缺少值,系統會將該元件視為屬性設為 '',只有在該元件為空白時才會比對。

使用字串時,如果您希望萬用字元用於建構的 URLPattern,則必須明確加入萬用字元。

// p1 and p2 are equivalent.
const p1 = new URLPattern('/foo', location.origin);
const p2 = new URLPattern({
  protocol: location.protocol,
  hostname: location.hostname,
  pathname: '/foo',
  search: '',
  hash: '',
});

// p3 and p4 are equivalent.
const p3 = new URLPattern('/foo?*#*', location.origin);
const p4 = new URLPattern({
  protocol: location.protocol,
  hostname: location.hostname,
  pathname: '/foo',
});

您也應注意,將字串模式剖析成其元件可能會造成模糊不清的情況。有些字元 (例如 :) 會出現在網址中,但在模式比對語法中也有特殊意義。為了避免混淆,URLPattern 建構函式會假設任何特殊字元都是模式的一部分,而非網址的一部分。如果您希望系統將含糊字元解讀為網址的一部分,請務必在以字串提供時,使用 \` character. For example, the literal URLabout:blankshould be escaped as`about\:blank'` 逸出該字元。

使用模式

建構 URLPattern 後,您可以使用兩種方法。test()exec() 方法都採用相同的輸入內容,並使用相同的演算法檢查是否相符,唯一的差異在於回傳值。如果指定的輸入內容有相符項目,test() 會傳回 true,否則會傳回 falseexec() 會傳回相符項目的詳細資訊,以及擷取群組,如果沒有相符項目,則會傳回 null。以下範例示範如何使用 exec(),但如果您只需要簡單的布林值傳回值,可以將 test() 換成任何一個。

如要使用 test()exec() 方法,其中一種方法是傳入字串。與建構函式支援的情況類似,如果提供單一字串,該字串應為完整網址,包括來源。如果提供兩個字串,系統會將第二個字串視為 baseURL 值,並根據該值評估第一個字串。

const p = new URLPattern({
  pathname: '/foo/:image.jpg',
  baseURL: 'https://example.com',
});

const result = p.exec('https://example.com/foo/cat.jpg');
// result will contain info about the successful match.
// const result = p.exec('/foo/cat.jpg', 'https://example.com')
// is equivalent, using the baseURL syntax.

const noMatchResult = p.exec('https://example.com/bar');
// noMatchResult will be null.

或者,您也可以傳遞建構函式支援的相同類型物件,其中屬性只設為您想比對的網址部分。

const p = new URLPattern({pathname: '/foo/:image.jpg'});

const result = p.exec({pathname: '/foo/:image.jpg'});
// result will contain info about the successful match.

在含有萬用字元或符記的 URLPattern 上使用 exec() 時,傳回值可讓您瞭解輸入網址中對應的值相關資訊。這樣一來,您就不必自行剖析這些值。

const p = new URLPattern({
  hostname: ':subdomain.example.com',
  pathname: '/*/:image.jpg'
});

const result = p.exec('https://imagecdn1.example.com/foo/cat.jpg');
// result.hostname.groups.subdomain will be 'imagecdn1'
// result.pathname.groups[0] will be 'foo', corresponding to *
// result.pathname.groups.image will be 'cat'

匿名和命名群組

將網址字串傳遞至 exec() 時,系統會傳回一個值,指出哪些部分與模式的所有群組相符。

傳回值具有與 URLPattern 元件 (例如 pathname) 相對應的屬性。因此,如果群組已定義為 URLPatternpathname 部分,則可在傳回值的 pathname.groups 中找到相符項目。系統會根據對應的模式是匿名或命名群組,以不同方式表示相符項目。

您可以使用陣列索引存取匿名模式比對的值。如果有多個匿名模式,索引 0 會代表最左邊模式的配對值,而 1 和其他索引則會用於後續模式。

在模式中使用命名群組時,系統會將相符項目公開為屬性,其名稱會對應至各個群組名稱。

Unicode 支援和正規化

URLPattern 支援多種 Unicode 字元。

  • 已命名群組 (例如 :café) 可包含萬國碼 (Unicode) 字元。適用於有效 JavaScript 識別碼 的規則,也適用於命名群組。

  • 模式內的文字會自動根據特定元件的網址編碼規則進行編碼。pathname 中的 Unicode 字元會使用百分比編碼,因此 pathname 模式 (例如 /café) 會自動標準化為 /caf%C3%A9hostname 中的萬國碼字元會自動使用 Punycode 編碼,而非百分比編碼。

  • 規則運算式群組只能包含 ASCII 字元。規則運算式語法讓在這些群組中自動編碼萬國碼 (Unicode) 字元變得困難且不安全。如果您想要比對規則運算式群組中的 Unicode 字元,您必須手動編碼其百分比,例如使用 (caf%C3%A9) 來比對 café

除了對 Unicode 字元編碼以外,URLPattern 也會執行網址正規化。舉例來說,pathname 元件中的 /foo/./bar 會折疊為等同的 /foo/bar

如果不確定指定的輸入模式是否已正規化,請使用瀏覽器的DevTools檢查建構的 URLPattern 例項。

全面整合使用

下方內嵌的 Glitch 示範說明位於服務工作站 fetch event handler 中的 URLPattern 核心用途,將特定模式對應至可產生網路要求回應的非同步函式。這個範例中的概念也適用於其他路由情況,無論是伺服器端還是用戶端。

意見回饋與未來計畫

雖然 URLPattern 的基本功能已在 Chrome 和 Edge 上推出,但我們也計畫新增其他功能。URLPattern 的部分功能仍在開發中,且有許多未解決的問題,關於特定行為仍有待改進。歡迎您試用 URLPattern,並透過 GitHub 問題提供任何意見回饋。

支援範本

path-to-regexp 程式庫提供 compile() function,可有效反轉路由行為。compile() 會使用模式和值當做符記預留位置,並傳回字串,做為符記預留位置的網址路徑。

我們希望日後將這項功能加入 URLPattern,但這不在初始版本的範圍內。

啟用未來的網頁平台功能

假設 URLPattern 成為網路平台的固定部分,其他可從路由或模式比對中受益的功能,就能以此做為基礎元素來建構。

我們目前正討論如何使用 URLPattern 實作建議功能,例如服務工作者範圍模式比對使用 PWA 做為檔案處理常式,以及推測預先擷取

特別銘謝

如需完整的致謝清單,請參閱原始說明文件