發布日期:2021 年 7 月 22 日
路徑是每個網頁應用程式的關鍵環節。從本質上來說,路由會採用網址,並套用模式比對或其他應用程式專屬邏輯,然後通常會根據結果顯示網頁內容。您可以透過多種方式實作路由:
- 將路徑對應至磁碟上檔案的伺服器程式碼
- 單頁應用程式中的邏輯,會等待目前位置的變更,然後建立並顯示對應的 DOM 片段。
雖然沒有明確的標準,但網頁開發人員已傾向採用通用語法來表示網址路徑模式,這與 regular expressions 有許多共通之處,但會加入一些網域專屬的項目,例如用於比對路徑區隔的符記。Express 和 Ruby on Rails 等熱門伺服器端架構會使用這種語法 (或非常接近的語法),而 JavaScript 開發人員可以使用 path-to-regexp 或 regexpparam 等模組,將該邏輯新增至自己的程式碼。
URLPattern
是網頁平台的新增功能,以這些架構建立的基礎為基礎。其目標是統一路由模式語法,包括支援萬用字元、具名權杖群組、規則運算式群組和群組修飾符。以這個語法建立的 URLPattern 執行個體可以執行常見的路由工作,例如比對完整網址或網址 pathname,以及傳回有關權杖和群組比對的資訊。
直接在網頁平台中提供網址比對功能的另一個好處是,這樣一來,其他也需要比對網址的 API 就能共用常見的語法。
瀏覽器支援和 Polyfill
在 Chrome 和 Edge 95 以上版本中,URLPattern 預設為啟用。
urlpattern-polyfill 程式庫可在瀏覽器或 Node 等環境中使用 URLPattern 介面,這些環境缺乏內建支援。如果您使用 Polyfill,請務必使用功能偵測,確保只有在目前環境缺少支援時才載入。否則,您將失去 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,偶爾也會處理網址的 search 或 hash 部分。由於這些網址只用於獨立網頁應用程式內的同源路徑,因此一律不必檢查網址的來源部分。
考量來源後,就能開啟更多用途,例如在服務工作人員的 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 URLabout:blankshould be escaped as'about\:blank'` 逸出該字元 (以字串形式提供時)。
使用解鎖圖案
建構 URLPattern 後,您有兩種使用方式。test() 和 exec() 方法都採用相同的輸入內容,並使用相同的演算法檢查是否相符,兩者只在回傳值方面有所不同。如果給定輸入內容相符,test() 會傳回 true,否則會傳回 false。exec() 會傳回相符項目的詳細資訊和擷取群組,如果沒有相符項目,則會傳回 null。下列範例示範如何使用 exec(),但如果只想取得布林傳回值,可以將任何範例中的 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。因此,如果群組定義為 URLPattern 的 pathname 部分,則相符項目會出現在回傳值的 pathname.groups 中。如果對應模式是匿名或具名群組,系統會以不同方式呈現相符項目。
您可以使用陣列索引存取匿名模式比對的值。
如果有多個匿名模式,索引 0 代表最左側的相符值,而 1 和後續索引則用於後續模式。
在模式中使用具名群組時,相符項目會以屬性形式公開,屬性名稱對應於各個群組名稱。
Unicode 支援和正規化
URLPattern 支援 Unicode 字元的方式有幾種。
具名群組 (例如
:café) 可以包含 Unicode 字元。適用於有效 JavaScript 識別項的規則也適用於具名群組。模式中的文字會根據該特定元件的網址編碼規則自動編碼。
pathname中的 Unicode 字元會使用百分比編碼,因此pathname模式 (例如/café) 會自動正規化為/caf%C3%A9。hostname中的 Unicode 字元會自動使用 Punycode 編碼,而非百分比編碼。規則運算式群組只能包含 ASCII 字元。規則運算式語法會導致系統難以自動編碼這些群組中的 Unicode 字元,且不安全。如要在規則運算式群組中比對 Unicode 字元,您需要手動進行百分比編碼,例如
(caf%C3%A9)比對café。
除了編碼 Unicode 字元之外,URLPattern 也會執行網址正規化。舉例來說,pathname 元件中的 /foo/./bar 會摺疊為對等的 /foo/bar。
如果對特定輸入模式的正規化方式有疑問,請使用瀏覽器的 DevTools 檢查建構的 URLPattern 執行個體。
馬上開始全面整合吧!
Glitch 示範說明 URLPattern 的核心用途,也就是在服務工作站的 fetch event handler 中,將特定模式對應至非同步函式,產生網路要求的回應。這個範例中的概念也適用於其他伺服器端或用戶端路由情境。
意見回饋和未來計畫
雖然 Chrome 和 Edge 已支援 URLPattern 的基本功能,
但我們還計畫新增其他功能。URLPattern 的部分功能仍在開發中,且特定行為仍有許多待解決的問題,歡迎試用 URLPattern,並透過 GitHub 問題提供意見回饋。
支援範本
path-to-regexp 程式庫提供 compile() function,可有效反轉轉送行為。compile() 會採用模式和權杖預留位置的值,並傳回含有這些值的網址路徑字串。
我們希望日後能將這項功能 新增至 URLPattern,但這不屬於初始版本的範圍。
啟用未來的網頁平台功能
假設 URLPattern 成為網路平台既有的部分,其他可從路徑或模式比對獲益的功能,就能以它為基礎建構原始型別。
目前正在討論是否要將 URLPattern 用於建議功能,例如服務工作站範圍模式比對、將 PWA 設為檔案處理常式和推測預先擷取。
如需完整的致謝名單,請參閱原始說明文件。