Een aanpak voor het standaardiseren van veelvoorkomende gebruiksscenario's voor patroonmatching.
Achtergrond
Routing is een belangrijk onderdeel van elke webapplicatie. In de kern houdt routering in dat je een URL neemt, er patroonmatching of andere app-specifieke logica op toepast en vervolgens, meestal, webinhoud weergeeft op basis van het resultaat. Routering kan op een aantal manieren worden geïmplementeerd: het is soms code die op een server draait en die een pad naar bestanden op schijf toewijst, of logica in een app van één pagina die wacht op wijzigingen in de huidige locatie en een corresponderend stukje DOM creëert om weergave.
Hoewel er niet één definitieve standaard bestaat, zijn webontwikkelaars aangetrokken tot een gemeenschappelijke syntaxis voor het uitdrukken van URL-routeringspatronen die veel gemeen hebben met regular expressions
, maar met enkele domeinspecifieke toevoegingen zoals tokens voor het matchen van padsegmenten. Populaire server-side frameworks zoals Express en Ruby on Rails gebruiken deze syntaxis (of iets dat daar heel dicht bij in de buurt komt), en JavaScript-ontwikkelaars kunnen modules zoals path-to-regexp
of regexpparam
gebruiken om die logica aan hun eigen code toe te voegen.
URLPattern
is een toevoeging aan het webplatform dat voortbouwt op de basis die door deze frameworks is gelegd. Het doel is om de syntaxis van een routeringspatroon te standaardiseren, inclusief ondersteuning voor jokertekens, benoemde tokengroepen, reguliere expressiegroepen en groepsmodificatoren. URLPattern
instanties die met deze syntaxis zijn gemaakt, kunnen algemene routeringstaken uitvoeren, zoals matchen met volledige URL's of een URL- pathname
, en informatie retourneren over het token en groepsovereenkomsten.
Een ander voordeel van het rechtstreeks aanbieden van URL-matching op het webplatform is dat een gemeenschappelijke syntaxis vervolgens kan worden gedeeld met andere API's die ook moeten matchen met URL's.
Browserondersteuning en polyfills
URLPattern
is standaard ingeschakeld in Chrome en Edge versie 95 en hoger.
De urlpattern-polyfill
bibliotheek biedt een manier om de URLPattern
interface te gebruiken in browsers of omgevingen zoals Node die geen ingebouwde ondersteuning hebben. Als u de polyfill gebruikt, zorg er dan voor dat u functiedetectie gebruikt om ervoor te zorgen dat u deze alleen laadt als de huidige omgeving geen ondersteuning biedt. Anders verliest u een van de belangrijkste voordelen van URLPattern
: het feit dat ondersteuningsomgevingen geen aanvullende code hoeven te downloaden en te parseren om deze te kunnen gebruiken.
if (!(globalThis && 'URLPattern' in globalThis)) {
// URLPattern is not available, so the polyfill is needed.
}
Syntaxiscompatibiliteit
Een leidende filosofie voor URLPattern
is om heruitvinding te voorkomen. Als u al bekend bent met de routeringssyntaxis die wordt gebruikt in Express of Ruby on Rails, hoeft u niets nieuws te leren. Maar gezien de kleine verschillen tussen syntaxis in populaire routeringsbibliotheken, moest er iets worden gekozen als basissyntaxis, en de ontwerpers van URLPattern
besloten om de patroonsyntaxis van path-to-regexp
(maar niet het API-oppervlak) als uitgangspunt te gebruiken. .
Deze beslissing is genomen na nauw overleg met de huidige beheerder van path-to-regexp
.
De beste manier om vertrouwd te raken met de kern van de ondersteunde syntaxis is door de documentatie voor path-to-regexp
te raadplegen. U kunt de documentatie die bedoeld is voor publicatie op MDN lezen in de huidige thuisbasis op GitHub.
Extra functies
De syntaxis van URLPattern
is een superset van wat path-to-regexp
ondersteunt, aangezien URLPattern
een ongebruikelijke functie onder routeringsbibliotheken ondersteunt: matching origins , inclusief jokertekens in hostnamen. De meeste andere routeringsbibliotheken behandelen alleen de padnaam en af en toe het zoek- of hashgedeelte van een URL. Ze hoeven nooit het oorsprongsgedeelte van een URL te controleren, omdat ze alleen worden gebruikt voor routering van dezelfde oorsprong binnen een op zichzelf staande web-app.
Door rekening te houden met de oorsprong wordt de deur geopend voor aanvullende gebruiksscenario's, zoals het routeren van cross-origin-verzoeken binnen de fetch
van een servicemedewerker . Als u alleen URL's van dezelfde oorsprong doorstuurt, kunt u deze extra functie effectief negeren en URLPattern
gebruiken zoals andere bibliotheken.
Voorbeelden
Het patroon construeren
Om een URLPattern
te maken, geeft u de constructor ervan strings of een object door waarvan de eigenschappen informatie bevatten over het patroon waarmee moet worden vergeleken.
Het doorgeven van een object biedt de meest expliciete controle over welk patroon moet worden gebruikt voor het matchen van elke URL-component. In zijn meest uitgebreide vorm kan dit er zo uitzien
const p = new URLPattern({
protocol: 'https',
username: '',
password: '',
hostname: 'example.com',
port: '',
pathname: '/foo/:image.jpg',
search: '*',
hash: '*',
});
Het opgeven van een lege tekenreeks voor een eigenschap komt alleen overeen als het overeenkomstige deel van de URL niet is ingesteld. Het jokerteken *
komt overeen met elke waarde voor een bepaald deel van de URL.
De constructor biedt verschillende snelkoppelingen voor eenvoudiger gebruik. Het volledig weglaten van search
en hash
, of andere eigenschappen, staat gelijk aan het instellen ervan op het jokerteken '*'
. Het bovenstaande voorbeeld kan worden vereenvoudigd tot
const p = new URLPattern({
protocol: 'https',
username: '',
password: '',
hostname: 'example.com',
port: '',
pathname: '/foo/:image.jpg',
});
Als extra snelkoppeling kan alle informatie over de oorsprong worden verstrekt in één enkele eigenschap, baseURL
, die leidt naar
const p = new URLPattern({
pathname: '/foo/:image.jpg',
baseURL: 'https://example.com',
});
Bij al deze voorbeelden wordt ervan uitgegaan dat uw gebruiksscenario het matchen van de oorsprong omvat. Als u alleen geïnteresseerd bent in matching op de andere delen van de URL, met uitzondering van de oorsprong (zoals het geval is voor veel "traditionele" routeringsscenario's met één oorsprong), dan kunt u de oorsprongsinformatie volledig weglaten en slechts een combinatie opgeven van de eigenschappen pathname
, search
en hash
. Net als voorheen worden weggelaten eigenschappen behandeld alsof ze zijn ingesteld op het jokertekenpatroon *
.
const p = new URLPattern({pathname: '/foo/:image.jpg'});
Als alternatief voor het doorgeven van een object aan de constructor kunt u één of twee strings opgeven. Als er één tekenreeks wordt opgegeven, moet deze een volledig URL-patroon vertegenwoordigen, inclusief patrooninformatie die wordt gebruikt om overeen te komen met de oorsprong. Als u twee tekenreeksen opgeeft, wordt de tweede tekenreeks gebruikt als baseURL
en wordt de eerste tekenreeks beschouwd als relatief ten opzichte van die basis.
Of er nu één of twee tekenreeksen worden opgegeven, de URLPattern
constructor parseert het volledige URL-patroon, verdeelt het in URL-componenten en wijst elk deel van het grotere patroon toe aan de overeenkomstige component. Dit betekent dat onder de motorkap elk URLPattern
dat met tekenreeksen is gemaakt, uiteindelijk op dezelfde manier wordt weergegeven als een equivalent URLPattern
dat met een object is gemaakt. De strings-constructor is slechts een snelkoppeling, voor degenen die de voorkeur geven aan een minder uitgebreide interface.
const p = new URLPattern('https://example.com/foo/:image.jpg?*#*');
Wanneer u strings gebruikt om een URLPattern
te maken, zijn er enkele kanttekeningen waarmee u rekening moet houden.
Het weglaten van een eigenschap wanneer u een object gebruikt om URLPattern
te construeren, komt overeen met het opgeven van een jokerteken *
voor die eigenschap. Wanneer het volledige URL-tekenreekspatroon wordt geparseerd en een van de URL-componenten een waarde mist, wordt deze behandeld alsof de eigenschap van de component is ingesteld op ''
, wat alleen overeenkomt als die component leeg is.
Wanneer u tekenreeksen gebruikt, moet u de jokertekens expliciet opnemen als u wilt dat ze worden gebruikt in de geconstrueerde 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',
});
Houd er ook rekening mee dat het ontleden van een tekenreekspatroon in zijn componenten mogelijk dubbelzinnig is. Er zijn tekens, zoals :
, die voorkomen in URL's, maar die ook een speciale betekenis hebben in de syntaxis van patroonvergelijking. Om deze dubbelzinnigheid te voorkomen, gaat de URLPattern
constructor ervan uit dat al deze speciale tekens deel uitmaken van een patroon en niet van de URL. Als u wilt dat een dubbelzinnig teken wordt geïnterpreteerd als onderdeel van de URL, zorg er dan voor dat u er een \` character. For example, the literal URL
should be escaped as
'about\:blank'` wanneer deze als tekenreeks wordt opgegeven.
Het patroon gebruiken
Nadat u een URLPattern
heeft gemaakt, heeft u twee opties om deze te gebruiken. De methoden test()
en exec()
gebruiken beide dezelfde invoer en gebruiken hetzelfde algoritme om te controleren op een overeenkomst, en verschillen alleen in hun geretourneerde waarde. test()
retourneert true
als er een overeenkomst is voor de gegeven invoer, en false
anders. exec()
retourneert gedetailleerde informatie over de match samen met capture-groepen, of null
als er geen match is. De volgende voorbeelden demonstreren het gebruik van exec()
, maar u kunt test()
voor elk ervan inruilen als u alleen een eenvoudige Booleaanse retourwaarde wilt.
Eén manier om de methoden test()
en exec()
te gebruiken is door tekenreeksen door te geven. Vergelijkbaar met wat de constructor ondersteunt: als er een enkele tekenreeks wordt opgegeven, moet deze een volledige URL zijn, inclusief de oorsprong. Als er twee tekenreeksen zijn opgegeven, wordt de tweede tekenreeks behandeld als een baseURL
waarde en wordt de eerste tekenreeks geëvalueerd als relatief ten opzichte van die basis.
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.
Als alternatief kunt u hetzelfde soort object doorgeven dat de constructor ondersteunt, met eigenschappen die zijn ingesteld op alleen de delen van de URL die u belangrijk vindt om te matchen.
const p = new URLPattern({pathname: '/foo/:image.jpg'});
const result = p.exec({pathname: '/foo/:image.jpg'});
// result will contain info about the successful match.
Wanneer u exec()
gebruikt op een URLPattern
die jokertekens of tokens bevat, geeft de geretourneerde waarde u informatie over wat de overeenkomstige waarden waren in de invoer-URL. Dit kan u de moeite besparen om die waarden zelf te moeten ontleden.
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'
Anonieme en benoemde groepen
Wanneer u een URL-tekenreeks doorgeeft aan exec()
, krijgt u een waarde terug die aangeeft welke delen overeenkomen met alle groepen van het patroon.
De geretourneerde waarde heeft eigenschappen die overeenkomen met de componenten van URLPattern
, zoals pathname
. Dus als een groep is gedefinieerd als onderdeel van het pathname
van URLPattern
, kunnen de overeenkomsten worden gevonden in de retourwaarde pathname.groups
. De overeenkomsten worden verschillend weergegeven, afhankelijk van of het overeenkomstige patroon een anonieme of benoemde groep was.
U kunt array-indexen gebruiken om toegang te krijgen tot de waarden voor een anonieme patroonovereenkomst. Als er meerdere anonieme patronen zijn, vertegenwoordigt index 0
de overeenkomende waarde voor het meest linkse patroon, waarbij 1
en verdere indices worden gebruikt voor volgende patronen.
Wanneer benoemde groepen in een patroon worden gebruikt, worden de overeenkomsten weergegeven als eigenschappen waarvan de namen overeenkomen met elke groepsnaam.
Unicode-ondersteuning en normalisatie
URLPattern
ondersteunt Unicode-tekens op een aantal verschillende manieren.
Benoemde groepen, zoals
:café
, kunnen Unicode-tekens bevatten. De regels die worden gebruikt voor geldige JavaScript-ID's zijn van toepassing op benoemde groepen.Tekst binnen een patroon wordt automatisch gecodeerd volgens dezelfde regels die worden gebruikt voor URL-codering van dat specifieke onderdeel. Unicode-tekens binnen
pathname
zijn procentgecodeerd , dus eenpathname
zoals/café
wordt automatisch genormaliseerd naar/caf%C3%A9
. Unicode-tekens in dehostname
worden automatisch gecodeerd met Punycode in plaats van met procentcodering.Reguliere expressiegroepen mogen alleen ASCII-tekens bevatten. De syntaxis van reguliere expressies maakt het moeilijk en onveilig om Unicode-tekens in deze groepen automatisch te coderen. Als u een Unicode-teken in een reguliere expressiegroep wilt matchen, moet u het handmatig procentueel coderen, bijvoorbeeld
(caf%C3%A9)
om overeen te komen metcafé
.
Naast het coderen van Unicode-tekens, voert URLPattern
ook URL-normalisatie uit. /foo/./bar
in de pathname
wordt bijvoorbeeld samengevouwen tot het equivalent /foo/bar
.
Als u twijfelt over hoe een bepaald invoerpatroon is genormaliseerd, inspecteer dan de geconstrueerde URLPattern
instantie met behulp van de DevTools van uw browser.
Alles op een rij zetten
De onderstaande Glitch-demo illustreert een kerngebruiksscenario van URLPattern
in de fetch event handler
van een servicemedewerker, waarbij specifieke patronen worden toegewezen aan asynchrone functies die een reactie op netwerkverzoeken kunnen genereren. De concepten in dit voorbeeld kunnen ook worden toegepast op andere routeringsscenario's, zowel aan de serverzijde als aan de clientzijde.
Feedback en toekomstplannen
Hoewel de basisfunctionaliteit voor URLPattern
in Chrome en Edge is opgenomen, zijn er toevoegingen gepland. Sommige aspecten van URLPattern
zijn nog in ontwikkeling en er zijn een aantal open vragen over specifiek gedrag die mogelijk nog verder worden verfijnd. We raden u aan URLPattern
uit te proberen en feedback te geven via een GitHub-probleem .
Ondersteuning voor sjablonen
De path-to-regexp
bibliotheek biedt een compile() function
die het routeringsgedrag effectief omkeert. compile()
neemt een patroon en waarden voor de tijdelijke aanduidingen voor het token, en retourneert een tekenreeks voor een URL-pad waarin deze waarden zijn vervangen.
We hopen dit in de toekomst aan URLPattern toe te voegen , maar dit valt niet binnen de reikwijdte van de eerste release.
Toekomstige webplatformfuncties mogelijk maken
Ervan uitgaande dat URLPattern
een gevestigd onderdeel van het webplatform wordt, kunnen andere functies die baat zouden kunnen hebben bij routering of patroonmatching er als primitief bovenop bouwen.
Er zijn voortdurende discussies over het gebruik van URLPattern
voor voorgestelde functies, zoals het matchen van scopepatronen van servicemedewerkers , PWA's als bestandshandlers en speculatief prefetchen .
Dankbetuigingen
Zie het originele uitlegdocument voor een volledige lijst met dankbetuigingen.