URLPattern ermöglicht Routing auf der Webplattform

Veröffentlicht: 22. Juli 2021

Routing ist ein wichtiger Bestandteil jeder Webanwendung. Beim Routing wird eine URL verwendet, auf die ein Musterabgleich oder eine andere appspezifische Logik angewendet wird. Anschließend werden in der Regel Webinhalte basierend auf dem Ergebnis angezeigt. Das Routing kann auf verschiedene Arten implementiert werden:

  • Servercode, der Pfade Dateien auf einer Festplatte zuordnet
  • Logik in einer Single-Page-App, die auf Änderungen am aktuellen Speicherort wartet und dann ein entsprechendes DOM-Element erstellt und anzeigt.

Es gibt zwar keinen einheitlichen Standard, aber Webentwickler haben sich für eine gemeinsame Syntax für die Darstellung von URL-Routingmustern entschieden, die viele Gemeinsamkeiten mit regular expressions aufweist, aber einige domainspezifische Ergänzungen wie Tokens für den Abgleich von Pfadsegmenten enthält. Beliebte 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 in ihren eigenen Code einzufügen.

URLPattern ist eine Ergänzung der Webplattform, die auf der Grundlage dieser Frameworks aufbaut. Ziel ist es, eine Syntax für Routingmuster zu standardisieren, einschließlich Unterstützung für Platzhalter, benannte Tokengruppen, Gruppen für reguläre Ausdrücke und Gruppenmodifikatoren. URLPattern-Instanzen, die mit dieser Syntax erstellt wurden, können allgemeine Routingaufgaben ausführen, z. B. den Abgleich mit vollständigen URLs oder einer URL pathname, und Informationen zu Token- und Gruppenübereinstimmungen zurückgeben.

Ein weiterer Vorteil der direkten Bereitstellung des URL-Abgleichs in der Webplattform besteht darin, dass eine gemeinsame Syntax mit anderen APIs verwendet werden kann, die ebenfalls URLs abgleichen 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-Schnittstelle in Browsern oder Umgebungen wie Node zu verwenden, die keine integrierte Unterstützung bieten. Wenn Sie das Polyfill verwenden, sollten Sie die Funktionserkennung nutzen, um es nur zu laden, wenn die aktuelle Umgebung keine Unterstützung bietet. Andernfalls verlieren Sie einen der wichtigsten Vorteile von URLPattern: Supportumgebungen müssen keinen zusätzlichen Code herunterladen und parsen, um ihn zu verwenden.

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

Syntaxkompatibilität

Ein Leitprinzip für URLPattern ist, dass das Rad nicht neu erfunden werden soll. Wenn Sie bereits mit der Routing-Syntax von Express oder Ruby on Rails vertraut sind, müssen Sie nichts Neues lernen. Angesichts der leichten Abweichungen zwischen den Syntaxen in beliebten Routing-Bibliotheken musste jedoch eine als Basissyntax ausgewählt werden. Die Entwickler von URLPattern entschieden sich für die Verwendung der Mustersyntax von path-to-regexp (jedoch nicht der API-Oberfläche) als Ausgangspunkt.

Diese Entscheidung wurde in enger Absprache mit dem aktuellen Maintainer von path-to-regexp getroffen.

Am besten machen Sie sich mit der unterstützten Syntax vertraut, indem Sie die Dokumentation für path-to-regexp lesen. Sie können die Dokumentation, die für die Veröffentlichung auf MDN vorgesehen ist, an ihrem aktuellen Speicherort auf GitHub lesen.

Zusätzliche Funktionen

Die Syntax von URLPattern ist eine Obermenge der von path-to-regexp unterstützten Syntax, da URLPattern eine unter Routingbibliotheken ungewöhnliche Funktion unterstützt: den Abgleich von Ursprüngen, einschließlich Platzhaltern in Hostnamen. Die meisten anderen Routing-Bibliotheken befassen sich nur mit dem pathname und gelegentlich mit dem search- oder hash-Teil einer URL. Sie müssen den Ursprungsteil einer URL nie prüfen, da sie nur für das Same-Origin-Routing innerhalb einer in sich geschlossenen Web-App verwendet werden.

Wenn Sie Ursprünge berücksichtigen, ergeben sich zusätzliche Anwendungsfälle, z. B. das Weiterleiten von ursprungsübergreifenden Anfragen innerhalb des fetch-Ereignishandlers eines Service Workers. 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 eine URLPattern erstellen möchten, übergeben Sie dem Konstruktor entweder Strings oder ein Objekt, dessen Eigenschaften Informationen zum abzugleichenden Muster enthalten.

Wenn Sie ein Objekt übergeben, haben Sie die expliziteste Kontrolle darüber, welches Muster für den Abgleich der einzelnen URL-Komponenten verwendet werden soll. Im ausführlichsten Fall kann 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 eine Eigenschaft einen leeren String angeben, wird nur eine Übereinstimmung erzielt, 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 Shortcuts für eine einfachere Verwendung. Wenn Sie search und hash oder andere Eigenschaften vollständig weglassen, entspricht das der Festlegung auf das Platzhalterzeichen '*'. Das 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 Abkürzung können alle Informationen zum Ursprung in einer einzigen Property angegeben werden: baseURL. Das führt zu

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

Bei allen diesen Beispielen wird davon ausgegangen, dass Ihr Anwendungsfall übereinstimmende Ursprünge umfasst. Wenn Sie nur an einem Abgleich mit den anderen Teilen der URL interessiert sind, ohne den Ursprung (wie es bei vielen Routing-Szenarien mit einem Ursprung der Fall ist), können Sie die Ursprungsinformationen vollständig weglassen und nur eine Kombination der Eigenschaften pathname, search und hash angeben. Wie bisher werden ausgelassene Attribute so behandelt, als wären sie auf das Platzhaltermuster * gesetzt.

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

Alternativ zur Übergabe eines Objekts an den Konstruktor können Sie einen oder zwei Strings angeben. Wenn ein String angegeben wird, sollte er ein vollständiges URL-Muster darstellen, einschließlich der Musterinformationen, die zum Abgleichen des Ursprungs verwendet werden. Wenn Sie zwei Strings angeben, wird der zweite String als baseURL verwendet und der erste String relativ zu dieser Basis betrachtet.

Unabhängig davon, ob ein oder zwei Strings angegeben werden, parst der URLPattern-Konstruktor das vollständige URL-Muster, zerlegt es in URL-Komponenten und ordnet jeden Teil des größeren Musters der entsprechenden Komponente zu. Das bedeutet, dass jede URLPattern, die mit Strings erstellt wird, intern genauso dargestellt wird wie eine entsprechende URLPattern, die mit einem Objekt erstellt wird. Der Konstruktor für Strings ist nur eine Abkürzung für Nutzer, die eine weniger ausführliche Benutzeroberfläche bevorzugen.

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

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

Wenn Sie eine Property beim Erstellen von URLPattern mit einem Objekt weglassen, entspricht das der Angabe eines *-Platzhalters für diese Property. Wenn das Muster für den vollständigen URL-String geparst wird und für eine der URL-Komponenten kein Wert vorhanden ist, wird es so behandelt, als ob die Eigenschaft der Komponente auf '' gesetzt wäre. Dies führt nur zu einer Übereinstimmung, wenn die Komponente leer ist.

Wenn Sie Strings verwenden, müssen Sie die Platzhalter explizit einfügen, wenn sie im erstellten URLPattern verwendet werden sollen.

// 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 sollten Sie sich bewusst sein, 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 den Musterabgleich haben. Um diese Mehrdeutigkeit zu vermeiden, geht der URLPattern-Konstruktor davon aus, dass alle diese Sonderzeichen Teil eines Musters und nicht Teil der URL sind. Wenn ein mehrdeutiges Zeichen als Teil der URL interpretiert werden soll, müssen Sie es mit einem \` character. For example, the literal URLabout:blankshould be escaped as'about\:blank'` escapen, wenn es als String angegeben wird.

Muster verwenden

Nachdem Sie ein URLPattern erstellt haben, haben Sie zwei Möglichkeiten, es zu verwenden. Die Methoden test() und exec() verwenden beide dieselbe Eingabe und denselben Algorithmus, um nach einer Übereinstimmung zu suchen. Sie unterscheiden sich nur im Rückgabewert. test() gibt true zurück, wenn es eine Übereinstimmung für die angegebene Eingabe gibt, und andernfalls false. exec() gibt detaillierte Informationen zur Übereinstimmung zusammen mit Erfassungsgruppen zurück oder null, wenn keine Übereinstimmung vorhanden ist. In den folgenden Beispielen wird exec() verwendet. Sie können jedoch test() einsetzen, wenn Sie nur einen booleschen Rückgabewert benötigen.

Eine Möglichkeit, die Methoden test() und exec() zu verwenden, besteht darin, Strings zu übergeben. Ähnlich wie beim Konstruktor sollte es sich bei einem einzelnen String um eine vollständige URL einschließlich des Ursprungs handeln. Wenn zwei Strings angegeben werden, wird der zweite String als baseURL-Wert behandelt und der erste String 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 dasselbe Objekt übergeben, das vom Konstruktor unterstützt wird, wobei die Eigenschaften nur auf die Teile der URL festgelegt sind, die Sie abgleichen möchten.

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 ein URLPattern verwenden, das Platzhalter oder Tokens enthält, erhalten Sie im Rückgabewert Informationen dazu, welche Werte in der Eingabe-URL verwendet wurden. So müssen Sie diese Werte nicht selbst parsen.

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'

Anonyme 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 von URLPattern entsprechen, z. B. pathname. Wenn also eine Gruppe als Teil des pathname-Abschnitts von URLPattern definiert wurde, sind die Übereinstimmungen im pathname.groups des Rückgabewerts zu finden. Die Übereinstimmungen werden unterschiedlich dargestellt, je nachdem, ob das entsprechende Muster eine anonyme oder benannte Gruppe war.

Sie können mit Array-Indexen auf die Werte für einen anonymen Musterabgleich zugreifen. Wenn es mehrere anonyme Muster gibt, stellt der Index 0 den übereinstimmenden Wert für das Muster ganz links dar. Für nachfolgende Muster werden 1 und weitere Indexe verwendet.

Wenn Sie benannte Gruppen in einem Muster verwenden, werden die Übereinstimmungen als Eigenschaften mit Namen angezeigt, die den einzelnen Gruppennamen entsprechen.

Unterstützung für Unicode und Normalisierung

URLPattern unterstützt Unicode-Zeichen auf verschiedene Arten.

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

  • Text in einem Muster wird automatisch nach 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 hostname werden automatisch mit Punycode codiert und nicht mit der Prozentcodierung.

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

Neben der Codierung von Unicode-Zeichen führt URLPattern auch die URL-Normalisierung durch. /foo/./bar in der Komponente pathname wird beispielsweise auf das entsprechende /foo/bar reduziert.

Wenn Sie sich nicht sicher sind, wie ein bestimmtes Eingabemuster normalisiert wurde, können Sie die erstellte URLPattern-Instanz mit den DevTools Ihres Browsers untersuchen.

Zusammenfassung

In der Glitch-Demo wird ein wichtiger Anwendungsfall von URLPattern in einem fetch event handler eines Service Workers veranschaulicht, bei dem bestimmte Muster asynchronen Funktionen zugeordnet werden, die eine Antwort auf Netzwerkanfragen generieren können. Die Konzepte in diesem Beispiel können auch auf andere Routing-Szenarien angewendet werden, entweder serverseitig oder clientseitig.

Feedback und Zukunftspläne

Die grundlegenden Funktionen für URLPattern sind zwar in Chrome und Edge verfügbar, es sind aber noch weitere Funktionen geplant. Einige Aspekte von URLPattern befinden sich noch in der Entwicklung und es gibt eine Reihe von offenen Fragen zu bestimmten Verhaltensweisen, die möglicherweise noch verfeinert werden. Wir empfehlen Ihnen, URLPattern auszuprobieren und uns Feedback über ein GitHub-Problem zu geben.

Unterstützung für Vorlagen

Die path-to-regexp-Bibliothek stellt ein compile() function bereit, das das Routingverhalten effektiv umkehrt. compile() akzeptiert ein Muster und Werte für die Token-Platzhalter und gibt einen String für einen URL-Pfad mit den entsprechenden Werten zurück.

Wir hoffen, URLPattern in Zukunft zu ergänzen, aber das ist nicht im Umfang der ersten Version enthalten.

Zukünftige Webplattformfunktionen aktivieren

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

Es gibt laufende Diskussionen über die Verwendung von URLPattern für vorgeschlagene Funktionen wie Service Worker-Bereichsmusterabgleich, PWAs als Dateihandler und spekulatives Prefetching.

Eine vollständige Liste der Danksagungen finden Sie im ursprünglichen Explainer-Dokument.