URLPattern brengt routing naar het webplatform

Gepubliceerd: 22 juli 2021

Routing is een essentieel onderdeel van elke webapplicatie. In de kern neemt routing een URL, past er een patroonherkenning of andere applicatiespecifieke logica op toe en toont vervolgens, meestal, webinhoud op basis van het resultaat. Routing kan op verschillende manieren worden geïmplementeerd:

  • Servercode die paden koppelt aan bestanden op een schijf.
  • Logica in een single-page applicatie die wacht op wijzigingen in de huidige locatie, waarna een overeenkomend DOM-element wordt aangemaakt en weergegeven.

Hoewel er geen eenduidige standaard is, hebben webontwikkelaars zich ontwikkeld tot een gangbare syntaxis voor het uitdrukken van URL-routeringspatronen die veel overeenkomsten vertoont 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 er sterk op lijkt), 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 die voortbouwt op de basis die door deze frameworks is gelegd. Het doel is om een ​​standaardisatie van de syntaxis voor routeringspatronen te realiseren, inclusief ondersteuning voor wildcards, benoemde tokengroepen, reguliere expressiegroepen en groepsmodifiers. URLPattern instanties die met deze syntaxis zijn gemaakt, kunnen gangbare routeringstaken uitvoeren, zoals het matchen van volledige URL's of een URL- pathname , en het retourneren van informatie over de token- en groepsmatches.

Een ander voordeel van het rechtstreeks aanbieden van URL-matching in het webplatform is dat een gemeenschappelijke syntaxis kan worden gedeeld met andere API's die ook URL's moeten matchen.

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.js die geen ingebouwde ondersteuning bieden. Als u de polyfill gebruikt, zorg er dan voor dat u feature detection gebruikt om ervoor te zorgen dat deze alleen wordt geladen als de huidige omgeving geen ondersteuning biedt. Anders verliest u een van de belangrijkste voordelen van URLPattern : het feit dat ondersteunende omgevingen geen extra code hoeven te downloaden en te parsen om het te kunnen gebruiken.

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

Syntactische compatibiliteit

Een leidende filosofie achter URLPattern is het vermijden van heruitvinding. Als je al bekend bent met de routing-syntaxis die gebruikt wordt in Express of Ruby on Rails, hoef je niets nieuws te leren. Maar gezien de kleine verschillen tussen de syntaxen van populaire routingbibliotheken, moest er een basissyntaxis gekozen worden. De ontwerpers van URLPattern besloten daarom de patroonsyntaxis van path-to-regexp (maar niet de API-interface) als uitgangspunt te nemen.

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. Je kunt de documentatie die bedoeld is voor publicatie op MDN lezen op de huidige locatie op GitHub.

Extra functies

De syntaxis van URLPattern is een uitgebreidere versie van wat path-to-regexp ondersteunt, omdat URLPattern een ongebruikelijke functie biedt voor routingbibliotheken: het matchen van origins , inclusief wildcards in hostnamen. De meeste andere routingbibliotheken werken alleen met het pad en soms met het zoek- of hashgedeelte van een URL. Ze hoeven nooit het origingedeelte van een URL te controleren, omdat ze alleen worden gebruikt voor same-origin routing binnen een op zichzelf staande webapplicatie.

Door rekening te houden met de oorsprong van de URL's ontstaan ​​er extra gebruiksmogelijkheden, zoals het routeren van cross-origin-verzoeken binnen de fetch -eventhandler van een service worker . Als je alleen URL's van dezelfde oorsprong routeert, kun je deze extra functie negeren en URLPattern gebruiken zoals andere bibliotheken.

Voorbeelden

Het patroon construeren

Om een URLPattern te creëren, geef je aan de constructor ervan strings of een object door waarvan de eigenschappen informatie bevatten over het patroon waarmee vergeleken moet worden.

Het doorgeven van een object biedt de meest expliciete controle over welk patroon moet worden gebruikt om elk URL-onderdeel te matchen. In de meest uitgebreide vorm kan dit er als volgt 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 werkt alleen als het corresponderende 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, is gelijk aan het instellen ervan op het wildcardteken '*' . Het 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 in één enkele eigenschap, baseURL , worden verstrekt, wat leidt tot

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

Al deze voorbeelden gaan ervan uit dat uw gebruiksscenario betrekking heeft op het matchen van oorsprongen. Als u alleen geïnteresseerd bent in het matchen van de andere delen van de URL, met uitzondering van de oorsprong (zoals het geval is bij veel single-origin routing-scenario's), dan kunt u de oorspronginformatie volledig weglaten en alleen een combinatie van de eigenschappen pathname , search en hash opgeven. Net als eerder worden weggelaten eigenschappen behandeld alsof ze zijn ingesteld op het wildcardpatroon * .

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

Als alternatief voor het doorgeven van een object aan de constructor, kunt u één of twee tekenreeksen opgeven. Als u één tekenreeks opgeeft, moet deze een volledig URL-patroon vertegenwoordigen, inclusief patrooninformatie die wordt gebruikt om de oorsprong te matchen. 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-URL.

Of er nu één of twee strings worden meegegeven, de URLPattern constructor analyseert het volledige URL-patroon, splitst het op in URL-componenten en koppelt elk deel van het grotere patroon aan de overeenkomstige component. Dit betekent dat elke URLPattern die met strings is gemaakt, in feite op dezelfde manier wordt weergegeven als een equivalente URLPattern die met een object is gemaakt. De strings-constructor is slechts een snelkoppeling voor diegenen die de voorkeur geven aan een minder uitgebreide interface.

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

Bij het gebruik van tekenreeksen om een URLPattern te creëren, zijn er een paar aandachtspunten.

Het weglaten van een eigenschap bij het construeren van URLPattern met behulp van een object is gelijk aan het opgeven van een * wildcard voor die eigenschap. Wanneer het volledige URL-stringpatroon wordt geparseerd, wordt, als een van de URL-componenten een waarde mist, dit behandeld alsof de eigenschap van de component is ingesteld op '' , wat alleen overeenkomt als die component leeg is.

Bij het gebruik van tekenreeksen moet u de wildcards expliciet opnemen als u wilt dat ze worden gebruikt in het 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 rekening mee dat het ontleden van een tekenreekspatroon in de afzonderlijke componenten potentieel ambigu kan zijn. Er zijn tekens, zoals de dubbele punt : , die in URL's voorkomen, maar ook een speciale betekenis hebben in de patroonherkenningssyntaxis. Om deze ambiguïteit te voorkomen, gaat de URLPattern constructor ervan uit dat al deze speciale tekens deel uitmaken van een patroon en niet van de URL zelf. Als u wilt dat een ambigu teken als onderdeel van de URL wordt geïnterpreteerd, moet u het escapen met een \` character. For example, the literal URL should be escaped as 'about\:blank' wanneer deze als tekenreeks wordt aangeleverd.

Gebruik het patroon

Nadat je een URLPattern hebt geconstrueerd, heb je twee opties om deze te gebruiken. De methoden test() en exec() nemen beide dezelfde invoer en gebruiken hetzelfde algoritme om te controleren op een overeenkomst. Het enige verschil zit in de retourwaarde. test() ` retourneert true als er een overeenkomst is voor de gegeven invoer, en false anders. exec() retourneert gedetailleerde informatie over de overeenkomst, inclusief vastgelegde groepen, of null als er geen overeenkomst is. De volgende voorbeelden demonstreren het gebruik van exec() , maar je kunt test() gebruiken in plaats van een van deze voorbeelden als je alleen een booleaanse retourwaarde wilt.

Een manier om de methoden test() en exec() te gebruiken, is door strings door te geven. Net als bij de constructor geldt dat als er één string wordt meegegeven, dit een volledige URL moet zijn, inclusief de oorsprong. Als er twee strings worden meegegeven, wordt de tweede string behandeld als een baseURL waarde en wordt de eerste string geëvalueerd ten opzichte van die basis-URL.

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 type object doorgeven als datgene dat de constructor ondersteunt, met eigenschappen die zijn ingesteld op alleen de delen van de URL die u wilt 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 je exec() gebruikt op een URLPattern die wildcards of tokens bevat, geeft de retourwaarde informatie over de overeenkomstige waarden in de invoer-URL. Dit kan je de moeite besparen om die waarden zelf te extraheren.

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 je een URL-string doorgeeft aan exec() , krijg je een waarde terug die aangeeft welke gedeelten overeenkomen met alle groepen van het patroon.

De retourwaarde heeft eigenschappen die overeenkomen met de componenten van het URLPattern , zoals pathname . Dus als een groep is gedefinieerd als onderdeel van het pathname gedeelte van het URLPattern , dan zijn de overeenkomsten te vinden in pathname.groups in de retourwaarde. De overeenkomsten worden anders weergegeven, afhankelijk van of het corresponderende patroon een anonieme of een benoemde groep was.

Je kunt array-indexen gebruiken om de waarden voor een anoniem patroon te benaderen. Als er meerdere anonieme patronen zijn, vertegenwoordigt index 0 de overeenkomende waarde voor het meest linkse patroon, terwijl index 1 en alle volgende indexen worden gebruikt voor de daaropvolgende patronen.

Bij gebruik van benoemde groepen in een patroon worden de overeenkomsten weergegeven als eigenschappen waarvan de namen overeenkomen met de namen van de betreffende groepen.

Unicode-ondersteuning en -normalisatie

URLPattern ondersteunt Unicode-tekens op verschillende manieren.

  • Benoemde groepen, zoals :café , kunnen Unicode-tekens bevatten. De regels die gelden voor geldige JavaScript-identifiers zijn ook van toepassing op benoemde groepen.

  • Tekst binnen een patroon wordt automatisch gecodeerd volgens dezelfde regels als die gebruikt worden voor URL-codering van dat specifieke onderdeel. Unicode-tekens in pathname worden procentueel gecodeerd , dus een pathname zoals /café wordt automatisch genormaliseerd naar /caf%C3%A9 . Unicode-tekens in de hostname worden automatisch gecodeerd met Punycode in plaats van procentuele codering.

  • 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 dit handmatig procentueel coderen, bijvoorbeeld (caf%C3%A9) om café te matchen.

Naast het coderen van Unicode-tekens voert URLPattern ook URL-normalisatie uit. Zo wordt bijvoorbeeld /foo/./bar in het pathname samengevoegd tot het equivalente /foo/bar .

Als je twijfelt over hoe een bepaald invoerpatroon is genormaliseerd, inspecteer dan de geconstrueerde URLPattern instantie met behulp van de ontwikkelaarstools van je browser.

Zet alles bij elkaar.

De Glitch-demo illustreert een kerngebruiksscenario van URLPattern binnen de fetch event handler van een service worker. Hierbij worden specifieke patronen gekoppeld 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 server- als aan de clientzijde.

Feedback en toekomstplannen

Hoewel de basisfunctionaliteit van URLPattern al beschikbaar is in Chrome en Edge, staan ​​er nog uitbreidingen op de planning. Sommige aspecten van URLPattern worden nog ontwikkeld en er zijn nog een aantal open vragen over specifieke gedragingen die mogelijk nog verfijnd moeten worden. We moedigen u aan om URLPattern uit te proberen en uw feedback te geven via een GitHub-issue .

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 token-placeholders en retourneert een tekenreeks voor een URL-pad waarin die waarden zijn vervangen.

We hopen dit in de toekomst aan URLPattern toe te voegen , maar het valt buiten de scope van de eerste release.

Schakel toekomstige webplatformfuncties in

Ervan uitgaande dat URLPattern een vast onderdeel van het webplatform wordt, kunnen andere functies die baat hebben bij routing of patroonherkenning daarop voortbouwen als een primitieve basis.

Er zijn lopende discussies over het gebruik van URLPattern voor voorgestelde functies zoals patroonherkenning binnen de scope van service workers , PWA's als bestandsverwerkers en speculatief prefetching .

Zie het oorspronkelijke toelichtingsdocument voor een volledige lijst met dankbetuigingen.