URLPattern ermöglicht Routing auf der Webplattform

Ein Ansatz zur Standardisierung häufiger Anwendungsfälle für Musterabgleiche.

Das Routing ist ein wichtiger Bestandteil jeder Webanwendung. Beim Routing wird zuerst eine URL genommen, ein Musterabgleich oder eine andere anwendungsspezifische Logik darauf angewendet und dann werden in der Regel Webinhalte basierend auf dem Ergebnis angezeigt. Das Routing kann auf unterschiedliche Weise implementiert werden: Manchmal ist es Code, der auf einem Server ausgeführt wird und einen Pfad zu Dateien auf dem Laufwerk zuordnet, oder Logik in einer Single-Page-App, die auf Änderungen am aktuellen Standort wartet und ein entsprechendes DOM-Element zum Anzeigen erstellt.

Es gibt zwar keinen eindeutigen Standard, aber Webentwickler haben sich für eine gemeinsame Syntax zum Ausdrucken von URL-Routing-Mustern entschieden, die viel mit regular expressions gemeinsam haben, aber einige domainspezifische Ergänzungen wie Tokens für übereinstimmende Pfadsegmente enthalten. Gängige serverseitige Frameworks wie Express und Ruby on Rails verwenden diese Syntax (oder eine sehr ähnliche) und JavaScript-Entwickler können Module wie path-to-regexp oder regexpparam verwenden, um diese Logik ihrem eigenen Code hinzuzufügen.

URLPattern ist eine Ergänzung der Webplattform, die auf der Grundlage dieser Frameworks aufbaut. Ziel ist es, eine Routingmustersyntax zu standardisieren, einschließlich der Unterstützung von Platzhaltern, benannten Tokengruppen, Gruppen für reguläre Ausdrücke und Gruppenmodifikatoren. Mit dieser Syntax erstellte URLPattern-Instanzen können gängige Routingaufgaben ausführen, z. B. das Abgleichen mit vollständigen URLs oder einer URL vom Typ pathname und das Zurückgeben von Informationen zu den Token- und Gruppenübereinstimmungen.

Ein weiterer Vorteil der URL-Übereinstimmung direkt auf der Webplattform besteht darin, dass eine gemeinsame Syntax dann für andere APIs verwendet werden kann, die ebenfalls mit URLs abgeglichen werden müssen.

Browserunterstützung und Polyfills

URLPattern ist in Chrome und Edge ab Version 95 standardmäßig aktiviert.

Die Bibliothek urlpattern-polyfill bietet eine Möglichkeit, die URLPattern-Benutzeroberfläche in Browsern oder Umgebungen wie Node zu verwenden, die keine integrierte Unterstützung bieten. Wenn du den Polyfill verwendest, solltest du die Featureerkennung nutzen, damit er nur geladen wird, wenn die aktuelle Umgebung es nicht unterstützt. Andernfalls verlieren Sie einen der Hauptvorteile von URLPattern: In Supportumgebungen muss kein zusätzlicher Code heruntergeladen und geparst werden, um ihn zu verwenden.

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

Syntaxkompatibilität

Eine Leitphilosophie für URLPattern ist es, Neuentwicklungen zu vermeiden. Wenn Sie bereits mit der in Express oder Ruby on Rails verwendeten Routingsyntax vertraut sind, sollten Sie nichts Neues lernen müssen. Aufgrund der leichten Abweichungen zwischen den Syntaxen in gängigen Routingbibliotheken musste jedoch eine Basissyntax ausgewählt werden. Die Designer von URLPattern entschieden sich, die Mustersyntax von path-to-regexp (nicht jedoch die API-Oberfläche) als Ausgangspunkt zu verwenden.

Diese Entscheidung wurde nach enger Absprache mit dem aktuellen Administrator von path-to-regexp getroffen.

Die beste Möglichkeit, sich mit dem Kern der unterstützten Syntax vertraut zu machen, ist die Dokumentation für path-to-regexp. Die Dokumentation für die Veröffentlichung auf MDN findest du an der aktuellen Startseite auf GitHub.

Zusätzliche Funktionen

Die Syntax von URLPattern ist eine Obermenge dessen, was path-to-regexp unterstützt, da URLPattern eine ungewöhnliche Funktion von Routingbibliotheken unterstützt: Abgleich von Ursprüngen, einschließlich Platzhaltern in Hostnamen. Die meisten anderen Routingbibliotheken befassen sich nur mit dem pathname und gelegentlich mit dem Such- oder Hash-Teil einer URL. Sie müssen nie den Ursprungsteil einer URL prüfen, da sie nur für das Routing innerhalb einer eigenständigen Webanwendung verwendet werden.

Wenn Sie Ursprünge berücksichtigen, eröffnen sich zusätzliche Anwendungsfälle, z. B. das Weiterleiten von Anfragen zwischen verschiedenen Ursprüngen innerhalb des fetch-Ereignishandlers eines Dienstarbeiters. Wenn Sie nur URLs mit demselben Ursprung weiterleiten, können Sie diese zusätzliche Funktion ignorieren und URLPattern wie andere Bibliotheken verwenden.

Beispiele

Muster erstellen

Wenn Sie ein URLPattern erstellen möchten, übergeben Sie dem Konstruktor entweder Strings oder ein Objekt, dessen Eigenschaften Informationen zum zu vergleichenden Muster enthalten.

Die Übergabe eines Objekts bietet die genaueste Kontrolle darüber, welches Muster für den Abgleich der einzelnen URL-Komponenten verwendet werden soll. Im schlimmsten Fall könnte das so aussehen:

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

Wenn Sie für ein Attribut einen leeren String angeben, ergibt sich nur dann eine Übereinstimmung, wenn der entsprechende Teil der URL nicht festgelegt ist. Der Platzhalter * entspricht jedem Wert für einen bestimmten Teil der URL.

Der Konstruktor bietet mehrere Tastenkombinationen für eine einfachere Verwendung. Das vollständige Weglassen von search und hash oder anderen Attributen entspricht dem Festlegen des Platzhalters '*'. Das obige Beispiel könnte so vereinfacht werden,

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

Als zusätzliche Vereinfachung können alle Informationen zur Quelle in einer einzigen Property (baseURL) angegeben werden.

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

Bei allen diesen Beispielen wird davon ausgegangen, dass Ihr Anwendungsfall das Abgleichen von Ursprüngen umfasst. Wenn Sie nur die Übereinstimmung mit den anderen Teilen der URL, ohne den Ursprung, anstreben (wie bei vielen „traditionellen“ Routingszenarien mit nur einem Ursprung), können Sie die Ursprungsinformationen vollständig weglassen und nur eine Kombination der Eigenschaften pathname, search und hash angeben. Wie bisher werden ausgelassene Properties so behandelt, als wären sie auf das Platzhaltermuster * festgelegt.

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

Anstatt ein Objekt an den Konstruktor zu übergeben, können Sie einen oder zwei Strings angeben. Wenn ein String angegeben wird, sollte er ein vollständiges URL-Muster darstellen, einschließlich Musterinformationen, die zum Abgleich mit dem Ursprung verwendet werden. Wenn Sie zwei Strings angeben, wird der zweite String als baseURL verwendet und der erste String wird relativ zu dieser Basis betrachtet.

Unabhängig davon, ob ein oder zwei Strings angegeben werden, wird das vollständige URL-Muster vom Konstruktor von URLPattern analysiert, in URL-Komponenten zerlegt und jeder Teil des größeren Musters der entsprechenden Komponente zugeordnet. Das bedeutet, dass jede mit Strings erstellte URLPattern im Grunde genauso dargestellt wird wie eine entsprechende URLPattern, die mit einem Objekt erstellt wurde. Der Konstruktor für Strings ist nur eine Verknüpfung für diejenigen, die eine weniger ausladende Benutzeroberfläche bevorzugen.

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

Wenn Sie Strings zum Erstellen einer URLPattern verwenden, müssen Sie einige Einschränkungen beachten.

Wenn Sie eine Property weglassen, wenn Sie URLPattern mit einem Objekt erstellen, entspricht das dem Angeben eines *-Platzhalters für diese Property. Wenn beim Parsen des vollständigen URL-Strings einer der URL-Komponenten ein Wert fehlt, wird davon ausgegangen, dass die Eigenschaft der Komponente auf '' festgelegt ist. Eine Übereinstimmung ist dann nur möglich, wenn die Komponente leer ist.

Wenn Sie Strings verwenden, müssen Sie die Platzhalter explizit angeben, damit sie in der erstellten URLPattern verwendet werden.

// 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',
});

Außerdem ist zu beachten, dass das Parsen eines Stringmusters in seine Komponenten potenziell mehrdeutig ist. Es gibt Zeichen wie :, die in URLs vorkommen, aber auch eine besondere Bedeutung in der Syntax für die Musterabgleich haben. Um diese Mehrdeutigkeit zu vermeiden, geht der URLPattern-Konstruktor davon aus, dass eines dieser Sonderzeichen Teil eines Musters und nicht Teil der URL ist. Wenn ein mehrdeutiges Zeichen als Teil der URL interpretiert werden soll, maskieren Sie es mit \` character. For example, the literal URLabout:blankshould be escaped as'about\:blank'`, wenn es als String bereitgestellt wird.

Muster verwenden

Nachdem Sie einen URLPattern erstellt haben, haben Sie zwei Möglichkeiten, ihn zu verwenden. Die Methoden test() und exec() nehmen dieselbe Eingabe an und verwenden denselben Algorithmus, um nach einer Übereinstimmung zu suchen. Sie unterscheiden sich nur durch den Rückgabewert. test() gibt true zurück, wenn eine Übereinstimmung mit der angegebenen Eingabe gefunden wird, andernfalls false. exec() gibt detaillierte Informationen zur Übereinstimmung zusammen mit Erfassungsgruppen zurück oder null, wenn keine Übereinstimmung gefunden wurde. In den folgenden Beispielen wird exec() verwendet. Sie können aber auch test() verwenden, wenn Sie nur einen einfachen booleschen Rückgabewert benötigen.

Eine Möglichkeit, die Methoden test() und exec() zu verwenden, besteht darin, Strings einzugeben. Ähnlich wie beim Konstruktor sollte ein einzelner String angegeben werden, der eine vollständige URL einschließlich des Ursprungs sein sollte. Wenn zwei Strings angegeben werden, wird der zweite String als baseURL-Wert behandelt und der erste String wird relativ zu dieser Basis ausgewertet.

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.

Alternativ können Sie dieselbe Art von Objekt übergeben, das der Konstruktor unterstützt, mit Properties, die nur auf die Teile der URL festgelegt sind, die abgeglichen werden sollen.

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

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

Wenn Sie exec() für eine URLPattern verwenden, die Platzhalter oder Tokens enthält, liefert der Rückgabewert Informationen über die entsprechenden Werte in der Eingabe-URL. So müssen Sie diese Werte nicht selbst herausfinden.

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'

Anononyme und benannte Gruppen

Wenn Sie einen URL-String an exec() übergeben, erhalten Sie einen Wert zurück, der angibt, welche Teile mit allen Gruppen des Musters übereinstimmen.

Der Rückgabewert hat Eigenschaften, die den Komponenten der URLPattern entsprechen, z. B. pathname. Wenn eine Gruppe als Teil des pathname-Teils von URLPattern definiert wurde, finden Sie die Übereinstimmungen in pathname.groups des Rückgabewerts. Die Übereinstimmungen werden unterschiedlich dargestellt, je nachdem, ob das entsprechende Muster eine anonyme oder eine benannte Gruppe war.

Sie können Arrayindizes verwenden, um auf die Werte für eine anonyme Musterübereinstimmung zuzugreifen. Wenn mehrere anonyme Muster vorhanden sind, stellt der Index 0 den übereinstimmenden Wert für das ganz links stehende Muster dar, wobei 1 und weitere Indexe für nachfolgende Muster verwendet werden.

Wenn Sie benannte Gruppen in einem Muster verwenden, werden die Übereinstimmungen als Properties angezeigt, deren Namen den jeweiligen Gruppennamen entsprechen.

Unicode-Unterstützung und ‑Normalisierung

URLPattern unterstützt Unicode-Zeichen auf verschiedene Arten.

  • Benannte Gruppen wie :café können Unicode-Zeichen enthalten. Die Regeln für gültige JavaScript-IDs gelten auch für benannte Gruppen.

  • Text in einem Muster wird automatisch gemäß denselben Regeln codiert, die für die URL-Codierung der jeweiligen Komponente verwendet werden. Unicode-Zeichen in pathname werden prozentcodiert. Ein pathname-Muster wie /café wird also automatisch in /caf%C3%A9 normalisiert. Unicode-Zeichen in der hostname werden automatisch mit Punycode und nicht mit Prozentcodierung codiert.

  • Reguläre Ausdrucksgruppen dürfen nur ASCII-Zeichen enthalten. Die Syntax von regulären Ausdrücken macht es schwierig und unsicher, Unicode-Zeichen in diesen Gruppen automatisch zu codieren. Wenn Sie ein Unicode-Zeichen in einer regulären Ausdrucksgruppe abgleichen möchten, müssen Sie es manuell mit dem Prozentzeichen codieren, z. B. (caf%C3%A9) für café.

Neben der Codierung von Unicode-Zeichen führt URLPattern auch eine URL-Normalisierung durch. Beispiel: /foo/./bar in der Komponente pathname wird auf die entsprechende /foo/bar minimiert.

Wenn Sie sich nicht sicher sind, wie ein bestimmtes Eingabemuster normalisiert wurde, prüfen Sie die erstellte URLPattern-Instanz mit den DevTools Ihres Browsers.

Zusammenfassung

Die unten eingebettete Glitch-Demo veranschaulicht einen zentralen Anwendungsfall von URLPattern innerhalb der fetch event handler eines Service Workers. Dabei werden bestimmte Muster asynchronen Funktionen zugeordnet, die eine Antwort auf Netzwerkanfragen generieren können. Die Konzepte in diesem Beispiel können auch auf andere Routingszenarien angewendet werden, entweder server- oder clientseitig.

Feedback und zukünftige Pläne

Die grundlegenden Funktionen von URLPattern sind zwar in Chrome und Edge verfügbar, es sind jedoch Ergänzungen geplant. Einige Aspekte von URLPattern befinden sich noch in der Entwicklungsphase und es gibt eine Reihe von offenen Fragen zu bestimmten Verhaltensweisen, die noch optimiert werden können. Wir empfehlen dir, URLPattern auszuprobieren und uns Feedback über ein GitHub-Problem zu geben.

Unterstützung von Vorlagen

Die Bibliothek path-to-regexp stellt eine compile() function bereit, die das Routingverhalten effektiv umkehrt. compile() nimmt ein Muster und Werte für die Token-Platzhalter an und gibt einen String für einen URL-Pfad zurück, in dem diese Werte eingefügt sind.

Wir hoffen, diese Funktion in Zukunft URLPattern hinzuzufügen, sie ist aber nicht Teil der ersten Version.

Zukünftige Webplattformfunktionen ermöglichen

Angenommen, URLPattern wird ein etablierter Teil der Webplattform, können andere Funktionen, die von Routing oder Musterabgleich profitieren könnten, darauf aufbauen.

Es gibt laufende Diskussionen über die Verwendung von URLPattern für vorgeschlagene Funktionen wie Musterabgleich im Service Worker-Umfang, PWAs als Dateihandler und vorherige Datenabfrage.

Danksagungen

Eine vollständige Liste der Mitwirkenden finden Sie im ursprünglichen Erklärdokument.