一種將常見模式比對用途標準化的做法。
背景
路由是每個網頁應用程式的重要元素。在本質上,路由會擷取網址,並套用一些模式比對或其他應用程式專屬邏輯,然後通常會根據結果顯示網頁內容。您可以透過多種方式實作路由:有時是執行在伺服器上的程式碼,用來將路徑對應至磁碟上的檔案;有時則是單頁應用程式中的邏輯,用來等待目前位置的變更,並建立對應的 DOM 片段進行顯示。
雖然沒有明確的標準,但網頁開發人員傾向使用通用的語法來表示網址路徑模式,這些模式與 regular expressions
有許多共同之處,但也加入了一些特定領域的內容,例如用於比對路徑區段的符記。Express 和 Ruby on Rails 等熱門伺服器端架構都會使用這個語法 (或類似的語法),而 JavaScript 開發人員可以使用 path-to-regexp
或 regexpparam
等模組,在自己的程式碼中加入該邏輯。
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: '*',
});
只有在未設定網址的對應部分時,系統才會為屬性提供空字串。萬用字元 *
會比對網址指定部分的任何值。
建構函式提供多種快速鍵,可簡化使用方式。完全省略 search
和 hash
或任何其他屬性,等同於將這些屬性設為 '*'
萬用字元。上述範例可簡化為
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',
});
所有這些範例都假設您的用途涉及比對來源。如果您只想比對網址的其他部分,而非來源 (許多「傳統」單來源路由情況即屬此類),則可以完全省略來源資訊,只提供 pathname
、search
和 hash
屬性的組合。如同先前所述,系統會將省略的屬性視為設為 *
萬用字元模式。
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 URL
about:blankshould be escaped as
`about\:blank'` 逸出該字元。
使用模式
建構 URLPattern
後,您可以選擇兩種使用方式。test()
和 exec()
方法都採用相同的輸入內容,並使用相同的演算法檢查是否相符,唯一的差異在於回傳值。如果與指定輸入內容相符,test()
會傳回 true
,否則會傳回 false
。exec()
會傳回相符項目的詳細資訊,以及擷取群組,如果沒有相符項目,則會傳回 null
。以下範例示範如何使用 exec()
,但如果您只需要簡單的布林值傳回值,可以將 test()
換成任何一個 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
) 相對應的屬性。因此,如果群組已定義為 URLPattern
的 pathname
部分,則可在傳回值的 pathname.groups
中找到相符項目。系統會根據對應的模式是匿名或命名群組,以不同方式表示相符項目。
您可以使用陣列索引存取匿名模式比對的值。如果有多個匿名模式,索引 0
會代表最左邊模式的配對值,而 1
和其他索引則會用於後續模式。
在模式中使用命名群組時,系統會將相符項目公開為屬性,其名稱會對應至各個群組名稱。
Unicode 支援和正規化
URLPattern
支援多種 Unicode 字元。
命名群組 (例如
:café
) 可包含 Unicode 字元。適用於有效 JavaScript 識別碼 的規則也適用於命名群組。模式中的文字會根據用於該特定元件網址編碼的相同規則自動編碼。
pathname
中的 Unicode 字元會使用百分比編碼,因此pathname
模式 (例如/café
) 會自動標準化為/caf%C3%A9
。hostname
中的萬國碼字元會自動使用 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 做為檔案處理常式,以及推測預先擷取。
特別銘謝
如需完整的致謝清單,請參閱原始說明文件。