Italiano

Strumenti per sviluppatori · URL codificatore e decodificatore

escape() vs encodeURIComponent: come si è evoluta la codifica URL di JavaScript

· Sfondo

javascript codifica dell'URL storia

Tre generazioni di funzioni di codifica JavaScript URL
Illustrazione vettoriale originale ToolAcre

JavaScript ha avuto tre generazioni di funzioni di codifica URL e la più vecchia si nasconde ancora nel codice di produzione. Questo post spiega cosa fa di sbagliato escape(), perché ES3 ha aggiunto le funzioni URI e perché preservano ! *' ( ).

Il %u20AC in un registro legacy: l'inconfondibile impronta digitale di escape() e l'errore di decodifica che provoca

Un file JavaScript legacy contiene una chiamata di codifica URL che utilizza la funzione deprecata escape(). L'output in un file di registro o in un messaggio di errore include la sequenza %u20AC, un'impronta inconfondibile della funzione deprecata escape() che nessun altro utilizza. Questa sequenza non corrisponde ad alcuna codifica standard URL e un decodificatore basato sulle regole RFC 3986 o WHATWG non la riconoscerà. I dati non possono andare avanti e indietro attraverso strumenti moderni. È un segno comune del codice precedente a ES3 e non è stato aggiornato dagli anni '90.

La funzione escape() è stata progettata nell'era di Netscape, prima che JavaScript avesse standard o regole formali di codifica URL. Codifica la maggior parte dei caratteri nonASCII utilizzando la notazione %uXXXX, un codice esadecimale a quattro cifre che nessun altro utilizza e che nessuno standard definisce da nessuna parte. Ciò aveva senso per usi una tantum all'interno di un browser, ma interrompeva la compatibilità con gli standard URL e rendeva impossibile decodificare i dati altrove.

escape() e unescape(): un progetto dell'era Netscape: presupposti Latin-1, l'invenzione %uXXXX e perché non ha mai raggiunto nessuno standard

escape() e unescape() presuppongono che l'input sia Latin-1 (ISO 8859-1), la codifica dei caratteri precedente a UTF-8 e Unicode. Convertono ogni carattere in un codice esadecimale, utilizzando %XX per i caratteri latini ad alto bit-1 e %uXXXX per tutto ciò che non è latino-1. Un carattere non latino-1 come un emoji non può essere rappresentato affatto. Le funzioni sono semplici e veloci, ma sono anche completamente sbagliate per qualsiasi caso d'uso moderno.

Entrambe le funzioni sono state aggiunte a JavaScript prima che esistessero gli standard. Sono stati deprecati immediatamente dopo che ES3 ha introdotto la corretta codifica URL in 1999. Rimangono in JavaScript per compatibilità con le versioni precedenti: rimuoverli danneggerebbe il codice antico. Ma qualsiasi nuovo codice non dovrebbe mai usarli. Sono una reliquia dell'eredità.

ES3 (1999) aggiunge encodeURI ed encodeURIComponent — codifica percentuale UTF-8 allineata con RFC 2396

ES3 ha introdotto due funzioni: encodeURI e encodeURIComponent. Entrambi eseguono la codifica percentuale UTF-8: converte i caratteri nonASCII in UTF-8 byte, quindi scrive ciascun byte come %HH. Entrambi sono in linea con RFC 2396, che era attuale all'epoca. RFC 3986 è arrivato più tardi e non ha modificato il comportamento di codifica. Queste funzioni sono ancora oggi lo standard e dovrebbero essere utilizzate.

encodeURI è pensato per codificare un URI completo; encodeURIComponent è pensato per codificare un componente all'interno di URI, come un valore di query o un segmento di percorso. La differenza è assolutamente fondamentale e facile da fraintendere. encodeURI preserva i caratteri strutturali come: / ? # @ = & e ;. encodeURIComponent li codifica tutti, lasciandoli sicuri da incorporare all'interno di un file URI più grande.

Perché ! * ' ( ) non sono ancora codificati: i caratteri RFC 2396 'mark' sono congelati nella lingua dopo che RFC 3986 li ha spostati

Entrambe le funzioni lasciano questi caratteri non codificati: lettere, cifre, trattino (-), carattere di sottolineatura (_), punto (.), tilde (~) e i cinque segni di punteggiatura! *' ( ). I segni provenivano da RFC 2396, che li elencava come caratteri "segno" non riservati. RFC 3986 è uscito in 2005 e ha spostato questi cinque in una categoria diversa, ma JavaScript aveva già congelato encodeURI ed encodeURIComponent in 1999. Cambiare quali personaggi lasciare inalterati romperebbe il codice esistente, quindi sono rimasti.

La decisione di mantenere questi cinque marchi non codificati per compatibilità con le versioni precedenti significa che la codifica di JavaScript non corrisponde perfettamente né a RFC 3986 né allo standard WHATWG. È abbastanza vicino per un uso pratico e cambiarlo ora è completamente impossibile. Questa è una lezione sulla stabilità di API: una volta congelato il comportamento, non è possibile modificarlo anche se lo standard si evolve.

Esempio realizzato: la stessa stringa tramite escape, encodeURI e encodeURIComponent: tre output confrontati

Prendi la stringa "R&D (ricerca) = café". Eseguilo tramite escape(), encodeURI e encodeURIComponent. escape() produce "R%26D%20(research)%20%3D%20caf%E9's", mescolando parentesi e apostrofi non codificati con e commerciale ed uguali con codifica percentuale. encodeURI produce "R&D%20(research)%20=%20caf%C3%A9's", lasciando da soli la e commerciale e i segni di uguale perché sono strutturali. encodeURIComponent produce "R%26D%20%28research%29%20%3D%20caf%C3%A9%27s", codificando tutto, comprese parentesi e apostrofo.

Incolla la stessa stringa nel codificatore e decodificatore URL e passa da encodeURI a encodeURIComponent per vedere la differenza. Quindi controlla cosa produrrebbe escape() (puoi chiamarlo nella console del browser, anche se ti avviserà). Si vede subito che le tre funzioni producono tre risultati completamente diversi.

Migrazione da escape(): mappatura delle vecchie chiamate alla funzione moderna corretta e gestione dei dati %uXXXX memorizzati

Il vecchio codice che utilizza escape() deve essere aggiornato. Se escape() è stato utilizzato per codificare un componente URI, sostituirlo con encodeURIComponent. Se è stato utilizzato per codificare un URI completo, utilizzare encodeURI. Per i dati archiviati che contengono sequenze %uXXXX, è necessario un decodificatore personalizzato: converti ciascun %uXXXX in un punto di codice Unicode, quindi raccogli i punti di codice in una stringa. Il metodo unescape() integrato di JavaScript leggerà %uXXXX, ma il risultato potrebbe non essere corretto UTF-8.

Dopo aver sostituito escape(), testare il codice con stringhe contenenti caratteri nonASCII, punteggiatura e caratteri speciali. L'output dovrebbe ora corrispondere a quanto previsto dagli strumenti e dagli standard moderni. Se il tuo codice è significativamente precedente a ES3, potrebbe utilizzare anche altri modelli obsoleti; vale la pena fare un audit completo.

Cosa non copre: le API URL e URLSearchParams, che sono trattate separatamente

Le API URL e URLSearchParams, aggiunte molto più tardi, forniscono interfacce di livello superiore per la costruzione di URL e la codifica dei componenti. Gestiscono tutte le operazioni di escape automaticamente e corrispondono esattamente allo standard WHATWG URL. Sono il modo preferito per creare URL in modo programmatico nel moderno JavaScript.

Questo post copre solo le funzioni di codifica, non quelle API di livello superiore. URL e URLSearchParams analizzano la struttura, selezionano le regole del componente e serializzano il risultato, mentre encodeURIComponent trasforma una stringa fornita senza sapere dove verrà posizionata. Questa distinzione è il limite: migrare una vecchia chiamata escape() a seconda che gestisse un valore o un indirizzo, quindi prendere in considerazione la sostituzione della concatenazione manuale circostante con le API strutturate come refactor separato.

Conclusione: tre funzioni, una coppia sopravvissuta: come il codificatore e decodificatore URL mostra il moderno comportamento encodeURI ed encodeURIComponent fianco a fianco

Lo sviluppo moderno JavaScript dovrebbe utilizzare encodeURI o encodeURIComponent, mai escape(). Le funzioni sono state standardizzate in 1999 e da allora non sono cambiate. Codificano i caratteri nonASCII come UTF-8 byte e gestiscono correttamente i caratteri riservati standard. Lo strumento codificatore e decodificatore URL implementa entrambe le funzioni e ti consente di vedere il loro comportamento fianco a fianco, facilitando la scelta di quello giusto per il tuo componente.

Se incontri sequenze %u in vecchi log o dati archiviati, sono output di escape() e dovrebbero essere migrati. La migrazione è semplice una volta identificato il modello. Il codice moderno non dovrebbe mai produrli.