一種將常見模式比對用途標準化的做法。
背景
路由是每個網頁應用程式的重要元素。在本質上,路由會擷取網址,並套用某些模式比對或其他應用程式專屬邏輯,然後通常會根據結果顯示網頁內容。您可以透過多種方式實作路由:有時是執行在伺服器上的程式碼,將路徑對應至磁碟上的檔案;有時則是單頁應用程式中的邏輯,會等待目前位置的變更,並建立相應的 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()
和 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 做為檔案處理常式,以及推測預先擷取。
特別銘謝
如需完整的致謝清單,請參閱原始說明文件。