Data di pubblicazione: 22 luglio 2021
Il routing è un elemento chiave di ogni applicazione web. Il routing prende un URL, applica una corrispondenza di pattern o un'altra logica specifica dell'app e poi, di solito, visualizza i contenuti web in base al risultato. Il routing può essere implementato in diversi modi:
- Codice server che mappa i percorsi ai file su un disco
- Logica in un'app a una sola pagina che attende le modifiche alla posizione corrente, poi crea e visualizza un elemento DOM corrispondente.
Sebbene non esista uno standard definitivo, gli sviluppatori web hanno adottato una sintassi comune per esprimere i pattern di routing degli URL che condividono molti elementi con regular expressions, ma con alcune aggiunte specifiche del dominio, come i token per la corrispondenza dei segmenti di percorso.
Framework lato server popolari come
Express e
Ruby on Rails utilizzano questa sintassi (o
qualcosa di molto simile) e gli sviluppatori JavaScript possono utilizzare moduli come
path-to-regexp o
regexpparam per aggiungere questa
logica al proprio codice.
URLPattern
è un'aggiunta alla piattaforma web che si basa sulle fondamenta create
da questi framework. Il suo obiettivo è standardizzare una sintassi del pattern di routing,
incluso il supporto di caratteri jolly, gruppi di token denominati, gruppi di espressioni regolari
e modificatori di gruppo. Le istanze URLPattern create con questa sintassi
possono eseguire attività di routing comuni, come la corrispondenza con URL completi o con un URL
pathname,
e restituire informazioni sulle corrispondenze di token e gruppi.
Un altro vantaggio di fornire la corrispondenza degli URL direttamente nella piattaforma web è che è possibile condividere una sintassi comune con altre API che devono anche corrispondere agli URL.
Supporto del browser e polyfill
URLPattern è attivato per impostazione predefinita in Chrome ed Edge versione 95 e successive.
La libreria
urlpattern-polyfill
fornisce un modo per utilizzare l'interfaccia URLPattern nei browser
o in ambienti come Node che non dispongono di supporto integrato. Se
utilizzi il polyfill, assicurati di utilizzare il rilevamento delle funzionalità per assicurarti di caricarlo solo se l'ambiente attuale non lo supporta. In caso contrario,
perderai uno dei vantaggi principali di URLPattern: il fatto che
gli ambienti di assistenza non devono scaricare e analizzare codice aggiuntivo per
utilizzarlo.
if (!(globalThis && 'URLPattern' in globalThis)) {
// URLPattern is not available, so the polyfill is needed.
}
Compatibilità della sintassi
Una filosofia guida per URLPattern è quella di evitare la reinvenzione. Se hai già
familiarità con la sintassi di routing utilizzata in Express o Ruby on Rails, non dovresti
dover imparare nulla di nuovo. Tuttavia, date le lievi divergenze
tra le sintassi nelle librerie di routing più diffuse, è stato necessario scegliere una sintassi
di base e i progettisti di URLPattern hanno deciso di utilizzare la sintassi dei pattern
di path-to-regexp (anche se non la relativa superficie API) come punto di partenza.
Questa decisione è stata presa dopo un'attenta consultazione con l'attuale manutentore di
path-to-regexp.
Il modo migliore per acquisire familiarità con la sintassi supportata è consultare la documentazione per path-to-regexp. Puoi
leggere la documentazione
destinata alla pubblicazione su MDN nella sua attuale
posizione su GitHub.
Altre funzionalità
La sintassi di URLPattern è un superset di ciò che supporta path-to-regexp, in quanto URLPattern supporta una funzionalità non comune tra le librerie di routing: la corrispondenza delle origini, inclusi i caratteri jolly nei nomi host. La maggior parte delle altre librerie di routing gestisce solo il pathname e, occasionalmente, la parte search o hash di un URL. Non devono mai controllare la parte di origine di un URL, in quanto vengono utilizzati solo
per il routing della stessa origine all'interno di un'app web autonoma.
Tenere conto delle origini apre la strada a casi d'uso aggiuntivi, come
il routing delle richieste multiorigine all'interno di un
gestore di eventi fetch di un
service worker. Se stai instradando solo URL della stessa origine, puoi
ignorare questa funzionalità aggiuntiva e utilizzare URLPattern come
altre librerie.
Esempi
Costruzione del pattern
Per creare un URLPattern, passa al suo costruttore stringhe o un oggetto le cui
proprietà contengono informazioni sul pattern da confrontare.
Il passaggio di un oggetto offre il controllo più esplicito sul pattern da utilizzare per la corrispondenza di ogni componente dell'URL. Nella sua forma più dettagliata, può apparire così:
const p = new URLPattern({
protocol: 'https',
username: '',
password: '',
hostname: 'example.com',
port: '',
pathname: '/foo/:image.jpg',
search: '*',
hash: '*',
});
Se fornisci una stringa vuota per una proprietà, la corrispondenza verrà trovata solo se la parte corrispondente dell'URL non è impostata. Il carattere jolly * corrisponderà a qualsiasi valore per una determinata
parte dell'URL.
Il costruttore offre diverse scorciatoie per un utilizzo più semplice. L'omissione completa di
search e hash o di qualsiasi altra proprietà equivale a impostarle sul carattere jolly
'*'. L'esempio potrebbe essere semplificato in:
const p = new URLPattern({
protocol: 'https',
username: '',
password: '',
hostname: 'example.com',
port: '',
pathname: '/foo/:image.jpg',
});
Come ulteriore scorciatoia, tutte le informazioni sull'origine possono essere fornite in un'unica proprietà, baseURL, il che porta a
const p = new URLPattern({
pathname: '/foo/:image.jpg',
baseURL: 'https://example.com',
});
Tutti questi esempi presuppongono che il tuo caso d'uso preveda origini corrispondenti. Se
ti interessa solo la corrispondenza con le altre parti dell'URL, escludendo
l'origine (come avviene in molti scenari di routing a singola origine), puoi omettere completamente le informazioni sull'origine e fornire solo
una combinazione delle proprietà pathname, search e hash. Come in precedenza,
le proprietà omesse verranno trattate come se fossero impostate sul pattern
con carattere jolly *.
const p = new URLPattern({pathname: '/foo/:image.jpg'});
In alternativa al passaggio di un oggetto al costruttore, puoi fornire
una o due stringhe. Se viene fornita una stringa, questa deve rappresentare un pattern URL completo, incluse le informazioni sul pattern utilizzate per la corrispondenza con l'origine. Se fornisci due stringhe, la seconda viene utilizzata come baseURL e la prima viene considerata relativa a questa base.
Indipendentemente dal fatto che venga fornita una o due stringhe, il costruttore URLPattern analizzerà
l'intero pattern URL, suddividendolo in componenti URL e mappando ogni parte
del pattern più grande al componente corrispondente. Ciò significa che, internamente, ogni URLPattern creato con stringhe viene rappresentato
allo stesso modo di un URLPattern equivalente creato con un oggetto. Il costruttore di stringhe è solo una scorciatoia per chi preferisce un'interfaccia meno dettagliata.
const p = new URLPattern('https://example.com/foo/:image.jpg?*#*');
Quando utilizzi le stringhe per creare un URLPattern, ci sono alcune avvertenze da tenere a mente.
Omettere una proprietà quando si utilizza un oggetto per costruire URLPattern equivale a fornire un carattere jolly * per quella proprietà. Quando viene analizzato il pattern della stringa dell'URL completo, se a uno dei componenti dell'URL manca un valore, viene considerato come se la proprietà del componente fosse impostata su '', che corrisponderà solo quando il componente è vuoto.
Quando utilizzi le stringhe, devi includere esplicitamente i caratteri jolly se vuoi
che vengano utilizzati nel URLPattern creato.
// 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',
});
Devi anche essere consapevole che l'analisi di un pattern di stringa nei suoi componenti è
potenzialmente ambigua. Esistono caratteri, come :, che si trovano negli URL
ma hanno anche un significato speciale nella sintassi di corrispondenza dei pattern. Per evitare questa ambiguità, il costruttore URLPattern presuppone che tutti questi caratteri speciali facciano parte di un pattern, non dell'URL. Se vuoi che un carattere ambiguo venga interpretato come parte dell'URL, assicurati di eseguirne l'escape con un
\` character. For example, the literal URLabout:blankshould be escaped as'about\:blank'` quando viene fornito come stringa.
Utilizzare la sequenza
Dopo aver creato un URLPattern, hai due opzioni per utilizzarlo. I metodi
test() e exec() prendono lo stesso input e utilizzano lo stesso
algoritmo per verificare la corrispondenza e differiscono solo per il valore restituito. test()
restituisce true se viene trovata una corrispondenza per l'input specificato, altrimenti restituisce false.
exec() restituisce informazioni dettagliate sulla corrispondenza insieme ai gruppi di acquisizione,
o null se non è presente alcuna corrispondenza. Gli esempi seguenti mostrano l'utilizzo di
exec(), ma puoi sostituirlo con test() in uno qualsiasi di questi esempi se vuoi solo un
valore restituito booleano.
Un modo per utilizzare i metodi test() e exec() è passare le stringhe.
Analogamente a quanto supportato dal costruttore, se viene fornita una singola stringa, deve essere un URL completo, inclusa l'origine. Se vengono fornite due stringhe, la
seconda stringa viene trattata come valore baseURL e la prima stringa viene valutata
in relazione a questa base.
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.
In alternativa, puoi passare lo stesso tipo di oggetto supportato dal costruttore, con proprietà impostate solo sulle parti dell'URL che ti interessano per la corrispondenza.
const p = new URLPattern({pathname: '/foo/:image.jpg'});
const result = p.exec({pathname: '/foo/:image.jpg'});
// result will contain info about the successful match.
Quando utilizzi exec() su un URLPattern che contiene caratteri jolly o token, il
valore restituito ti fornirà informazioni sui valori corrispondenti
nell'URL di input. In questo modo non dovrai analizzare manualmente questi valori.
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'
Gruppi anonimi e denominati
Quando passi una stringa URL a exec(), ricevi un valore che indica quali parti corrispondono a tutti i gruppi del pattern.
Il valore restituito ha proprietà che corrispondono ai componenti di
URLPattern, come pathname. Pertanto, se un gruppo è stato definito come parte della
porzione pathname di URLPattern, le corrispondenze possono essere trovate in
pathname.groups del valore restituito. Le corrispondenze sono rappresentate in modo diverso
a seconda che il pattern corrispondente fosse un gruppo anonimo o denominato.
Puoi utilizzare gli indici degli array per accedere ai valori di una corrispondenza di pattern anonima.
Se sono presenti più pattern anonimi, l'indice 0 rappresenta il valore corrispondente
per quello più a sinistra, mentre 1 e gli indici successivi vengono utilizzati per i pattern
successivi.
Quando utilizzi gruppi denominati in un pattern, le corrispondenze vengono esposte come proprietà i cui nomi corrispondono a ogni nome del gruppo.
Supporto e normalizzazione Unicode
URLPattern supporta i caratteri Unicode in diversi modi.
I gruppi denominati, come
:café, possono contenere caratteri Unicode. Le regole utilizzate per identificatori JavaScript validi si applicano ai gruppi denominati.Il testo all'interno di un pattern verrà codificato automaticamente in base alle stesse regole utilizzate per la codifica URL di quel particolare componente. I caratteri Unicode all'interno di
pathnameverranno codificati in percentuale, quindi un patternpathnamecome/caféviene normalizzato automaticamente in/caf%C3%A9. I caratteri Unicode nelhostnamevengono codificati automaticamente utilizzando Punycode, anziché la codifica percentuale.I gruppi di espressioni regolari devono contenere solo caratteri ASCII. La sintassi delle espressioni regolari rende difficile e non sicuro codificare automaticamente i caratteri Unicode in questi gruppi. Se vuoi trovare una corrispondenza con un carattere Unicode in un gruppo di espressioni regolari, devi codificarlo manualmente in percentuale, ad esempio
(caf%C3%A9)per trovare una corrispondenza concafé.
Oltre a codificare i caratteri Unicode, URLPattern esegue anche la normalizzazione
dell'URL. Ad esempio, /foo/./bar nel componente pathname viene compresso nell'equivalente /foo/bar.
In caso di dubbi sulla normalizzazione di un determinato pattern di input, esamina l'istanza URLPattern creata utilizzando DevTools del browser.
Riassumendo
La demo di Glitch illustra un caso d'uso principale di URLPattern
all'interno di un service worker
fetch event handler,
mappando pattern specifici a funzioni asincrone che potrebbero generare una
risposta alle richieste di rete. I concetti di questo esempio possono essere applicati anche ad altri scenari di routing, lato server o lato client.
Feedback e piani futuri
Sebbene la funzionalità di base per URLPattern sia stata implementata in Chrome ed Edge,
sono previste aggiunte. Alcuni aspetti di URLPattern sono ancora in fase di sviluppo
e ci sono diverse
questioni aperte
su comportamenti specifici che potrebbero essere ancora perfezionati. Ti invitiamo a provare
URLPattern e a fornire feedback tramite una
segnalazione su GitHub.
Supporto per i modelli
La libreria path-to-regexp fornisce un
compile() function
che inverte efficacemente il comportamento di routing. compile() accetta un
pattern e valori per i segnaposto dei token e restituisce una stringa per un percorso URL
con i valori sostituiti.
Speriamo di aggiungere questa funzionalità a URLPattern in futuro, ma non rientra nell'ambito della release iniziale.
Attivare le funzionalità future della piattaforma web
Supponendo che URLPattern diventi una parte consolidata della piattaforma web, altre funzionalità che potrebbero trarre vantaggio dal routing o dalla corrispondenza di pattern possono basarsi su di essa come primitiva.
Sono in corso discussioni sull'utilizzo di URLPattern per le funzionalità proposte
come
corrispondenza del pattern dell'ambito del service worker,
PWA come gestori di file,
e
recupero speculativo.
Per un elenco completo dei ringraziamenti, consulta il documento esplicativo originale.