Vai al contenuto
OneKitly

Costruire un URL con parametri che sopravvive a un copia-incolla

Pubblicato il 11/08/2026 · 12 min di lettura · Strumenti per sviluppatori

Daniel Okonkwo

Daniel OkonkwoSviluppatore front-end e redattore Tech presso OneKitly

Performance web · Formati di file

Verificato su 4 fonti

Vedi il profilo
In breve

Una query string si rompe quando un carattere che significa qualcosa per l'URL — uno spazio, una e commerciale, un segno di uguale, un cancelletto — resta se stesso dentro un valore. La codifica percentuale risolve la cosa, ma le codifiche sono tre e divergono, e la divergenza si vede sullo spazio. encodeURIComponent scrive uno spazio come %20 e lascia intatti ! ' ( ) * ~. Il serializzatore application/x-www-form-urlencoded, quello che usano URLSearchParams e ogni modulo HTML, scrive uno spazio come + e codifica ! ' ( ) ~ lasciando intatto *. La RFC 3986 rigorosa codifica tutto ciò che sta fuori da A-Z a-z 0-9 - . _ ~, quindi fa l'escape anche di * e conserva ~. Questo generatore offre tutte e tre, e la sua modalità modulo è stata confrontata con l'URLSearchParams di Node su diciassette valori, fra cui un'emoji, un a capo e una stringa accentata: identica byte per byte ogni volta. Codifica davvero due volte: digita %20 come valore e ottieni %2520. È corretto — stai digitando un valore grezzo, non uno già codificato — e il parser dello strumento lo riporta al letterale %20. Il bug vero è altrove. Dagli un URL di base con un frammento, https://example.com/page#section, e la query viene aggiunta dopo il frammento: il parser di URL del browser riporta allora una parte query vuota e mette tutti i parametri dentro l'hash, dove nessun server li vedrà mai. Il suo parser butta via anche il frammento, e una sequenza di escape legacy come %E9 fallisce la decodifica, resta come testo letterale e ritorna come %25E9 alla costruzione successiva.

Tre codifiche, una differenza visibile: %20 o +. La modalità modulo del generatore riproduce URLSearchParams byte per byte su diciassette valori — ma dagli un URL di base con un frammento e ogni parametro finisce dentro l'hash, dove nessun server lo vede.

Due norme, e i browser applicano la più recente

La RFC 3986 è il documento più vecchio e quello che tutti citano. Divide i caratteri in non riservati — A-Z, a-z, 0-9 e i quattro segni - . _ ~ — e tutto il resto, riservato o da codificare in percentuale. È un modello pulito e non è quello che esegue il tuo browser. I browser applicano il WHATWG URL Standard, un documento vivo che specifica l'analisi e la serializzazione tramite più insiemi di codifica con nome, uno per parte dell'URL. I due concordano sui casi comuni e divergono ai margini, e ai margini un URL smette di funzionare.

Lo standard URL è esplicito su questo rapporto. Dice che usare il suo insieme di codifica «component» con UTF-8 dà risultati identici a encodeURIComponent di JavaScript. E definisce l'insieme application/x-www-form-urlencoded come l'insieme component più ! ' ( ) ~ — poi dice la stessa cosa al contrario, nella frase che vale la pena memorizzare: quell'insieme contiene tutti i code point tranne gli alfanumerici ASCII e * - . _ . Quattro caratteri. È l'intera lista sicura di un invio di modulo, e spiega a colpo d'occhio perché le due modalità divergono esattamente su ! ' ( ) ~ mentre entrambe lasciano stare l'asterisco.

La terza modalità del generatore, RFC 3986 rigorosa, è quella da usare quando un server firma l'URL. Prende l'output di encodeURIComponent e fa in più l'escape di ! ' ( ) * , lasciando stare ~, perché la tilde è non riservata nella RFC 3986 e farne l'escape cambierebbe la firma. I gateway di pagamento, le firme OAuth 1.0 e certe API aziendali più vecchie calcolano un hash sulla stringa codificata, quindi un codificatore che lascia un apostrofo così com'è produce un hash diverso dal loro e la richiesta viene rifiutata senza spiegazioni utilizzabili.

Sì, codifica due volte, ed è la risposta giusta

La doppia codifica è la lamentela classica contro i generatori di URL, perciò è stata provata direttamente. Digita %20 in un campo valore e l'output è %2520. Digita caf%C3%A9 e ottieni caf%25C3%25A9. Digita un semplice segno di percentuale e ottieni %25. Non è un bug: è la definizione del campo. La casella del valore contiene il valore che il tuo utente ha digitato, e se quel valore è davvero la sequenza c a f % 2 0, allora %2520 è l'unica codifica che la consegnerà.

Il modo per verificare se un generatore fa la cosa giusta non è guardare un output, ma fare un'andata e ritorno. Costruisci un URL, incollalo di nuovo nel campo di analisi dello strumento e ricostruiscilo. Sei valori hanno fatto quel ciclo — una frase accentata con una e commerciale, un segno più, un %20 letterale, un cancelletto dentro un valore, un valore vuoto e un oggetto JSON — e tutti e sei sono tornati identici byte per byte. Il %2520 incollato si è decodificato nel letterale %20, che si è ricodificato in %2520. Un generatore che togliesse uno strato per sembrare ordinato fallirebbe proprio qui, in silenzio, sull'unico valore che conta.

Il bug: un frammento nell'URL di base ingoia ogni parametro

Il generatore unisce la sua query alla base cercando un punto interrogativo: se la base ne ha già uno aggiunge con una e commerciale, altrimenti con un punto interrogativo. Entrambi i rami aggiungono in fondo. Un URL non funziona così. L'ordine delle parti è fisso — schema, autorità, percorso, query, frammento — e il frammento viene per ultimo, quindi tutto ciò che si scrive dopo appartiene a lui.

Metti la base su https://example.com/page#section, aggiungi q e page, e lo strumento stampa https://example.com/page#section?q=caf%C3%A9%20%26%20croissant&page=2. Sembra a posto. Consegna quella stringa al parser di URL del browser e riporta un percorso /page, una parte query vuota e un hash che contiene #section?q=caf%C3%A9%20%26%20croissant&page=2 — tutti i parametri dentro il frammento. Un frammento non viene mai inviato al server. La pagina si caricherà, nessun errore comparirà da nessuna parte, e i parametri semplicemente non esisteranno dal punto di vista del server. La variante con una query già presente, https://example.com/page?a=1#frag, racconta la stessa cosa: la parte query torna come ?a=1 e i nuovi parametri stanno nell'hash.

L'analisi ha il problema speculare: taglia l'input al primo cancelletto e butta via tutto ciò che segue. Incolla https://example.com/p?a=1#frag e la base torna come https://example.com/p, frammento sparito. Quindi non puoi usare lo strumento affatto su un URL che abbia un frammento: lo perde in entrata e piazza male la query in uscita. Finché non sarà corretto, il rimedio è togliere il frammento da solo, costruire la query e riassemblare a mano: base, poi query, poi cancelletto, in quest'ordine.

Tre cose minori da sapere prima di affidarcisi

Primo: una sequenza percentuale che non sa decodificare viene tenuta come testo letterale e poi ricodificata in uscita. Incolla un URL con a=%E9 — una sequenza Latin-1 a un byte, come ne emettono ancora moltissimi sistemi anteriori al 2010 — e il decodificatore solleva un errore, lo strumento lo cattura e tiene i tre caratteri % E 9 come valore. Ricostruisci e diventa a=%25E9, un URL diverso da quello che hai incollato. Nulla ti avvisa. La mossa sicura è controllare ogni parametro che torni contenendo un segno di percentuale.

Secondo, il generatore raggruppa i parametri per chiave invece di conservare l'ordine delle tue righe. Le righe a=1, b=2, a=3 escono come a=1&a=3&b=2: le due righe a vengono avvicinate e b scende. Per un normale server web è innocuo, dato che quasi nulla si cura dell'ordine dei parametri. Per una richiesta firmata no, perché la firma è calcolata sulla stringa esatta. Confronta l'output con l'ordine che hai digitato ogni volta che il destinatario calcola un hash sulla query.

Terzo, l'opzione di ordinamento delle chiavi ordina con il confronto sensibile alle impostazioni locali del browser, non per code point. Con le chiavi b, a, B e _x produce _x, a, b, B. Un ordinamento per code point — quello che specifica ogni schema di firma esistente — produce B, _x, a, b. I due divergono non appena le tue chiavi mescolano maiuscole e minuscole o iniziano con un trattino basso, che è proprio ciò che tendono a fare i nomi dei parametri di un'API firmata. Usa l'opzione per rendere leggibile un URL lungo; non usarla per canonizzarlo.

Due cose che fa bene e che è facile sbagliare. Le sue quattro sintassi per valori ripetuti codificano tutte le parentesi quadre: a[]=1 si scrive a%5B%5D=1 e a[0]=1 si scrive a%5B0%5D=1, il che è corretto secondo la RFC 3986, dove le parentesi quadre sono riservate ai letterali host IPv6 — e che PHP, Rails ed Express decodificano tutti. E in modalità virgola, anche la virgola fra i valori viene codificata: color=red,blue si scrive color=red%2Cblue: legale e sicuro con qualsiasi server che decodifichi prima di suddividere.

Lo stesso valore attraverso le tre codifiche del generatore, come le ha realmente prodotte
Valore digitatoencodeURIComponentx-www-form-urlencodedRFC 3986 rigorosa
two wordstwo%20wordstwo+wordstwo%20words
café & croissantcaf%C3%A9%20%26%20croissantcaf%C3%A9+%26+croissantcaf%C3%A9%20%26%20croissant
C'est (chouette) !C'est%20(chouette)%20!C%27est+%28chouette%29+%21C%27est%20%28chouette%29%20%21
~tilde*star~tilde*star%7Etilde*star~tilde%2Astar
a=b&c#da%3Db%26c%23da%3Db%26c%23da%3Db%26c%23d
%20 digitato letteralmente%2520%2520%2520
Generatore di query string URLCostruisci una query string URL da coppie chiave/valore, con codifica corretta, sintassi di array e preset UTM — oppure analizza un URL esistente.Prova lo strumento

Domande frequenti

Quale codifica scelgo se non so cosa si aspetta il server?
Scegli encodeURIComponent, la modalità predefinita. Uno spazio diventa %20, che ogni server decodifica correttamente, mentre il + è letto come spazio solo da codice che sa di leggere dati di modulo. Quell'asimmetria è tutta la ragione per preferire %20 in un URL che incollerai in un'email, in un messaggio di chat o in un foglio di calcolo: sopravvive alla lettura da parte di qualcosa che non sa che viene da un modulo. Passa a x-www-form-urlencoded solo quando riproduci ciò che invierebbe un modulo del browser — per esempio mentre indaghi perché un invio differisce dal tuo URL costruito a mano. Passa alla RFC 3986 rigorosa quando un server firma o calcola un hash sulla query string, perché gli escape aggiuntivi di ! ' ( ) * sono quelli che producono quasi tutte le librerie di firma.
Perché i miei parametri sono spariti quando il link finiva con #section?
Perché sono stati scritti dopo il frammento, e tutto ciò che segue un cancelletto è il frammento. Questo generatore aggiunge la query in fondo a ciò che gli hai dato come base, quindi una base https://example.com/page#section produce https://example.com/page#section?q=x, e il browser legge tutta la coda come un unico frammento. Un frammento è risolto interamente sul client; non fa parte della riga di richiesta e nessun server lo vede mai. Correggi a mano: prendi la base senza il frammento, aggiungi la query, poi rimetti il frammento proprio in fondo, ottenendo https://example.com/page?q=x#section. Se incolli quell'URL corretto di nuovo nello strumento, analizzerà bene la query ma perderà di nuovo il frammento, quindi tieni il frammento altrove mentre lavori.
Come invio una lista di valori per lo stesso parametro?
Non c'è una norma, ed è per questo che lo strumento offre quattro sintassi. Ripetere la chiave, color=red&color=blue, è ciò che produce un modulo HTML quando più caselle condividono un nome, ed è ciò che restituisce URLSearchParams.getAll; è il valore predefinito più sicuro. Le parentesi quadre, color[]=red&color[]=blue, sono una convenzione PHP che leggono anche Rails e diversi framework PHP. Le parentesi indicizzate, color[0]=red, conservano la posizione e si usano dove il server ricostruisce un array ordinato. Un valore unito da virgole, color=red,blue, è un solo parametro con un solo valore che il server suddivide da sé. Scegli quella che il tuo server documenta; se non ne documenta nessuna, ripeti la chiave. Nota che lo strumento codifica le parentesi e la virgola, il che è legale e che ognuno di quei framework decodifica prima di analizzare.
È prudente mettere un indirizzo email o un numero d'ordine in una query string?
Tecnicamente funzionerà, e conviene comunque evitarlo. Una query string fa parte dell'URL, e gli URL vengono scritti nella cronologia del browser, nei log di accesso del server, in quelli di proxy e CDN, e nell'intestazione Referer inviata a qualsiasi script di terze parti che la pagina carichi. Qualsiasi dato personale che ci metti viene copiato in tutti quei posti da sistemi a cui nessuno ha detto che era personale, e ci resta per il periodo di conservazione di ciascuno. Metti pure identificatori nella query — un id di prodotto, un numero di pagina, un nome di campagna — e metti tutto ciò che identifica una persona nel corpo di una richiesta POST, o dietro un token opaco breve che risolve il tuo stesso server. Lo stesso vale per qualsiasi cosa conceda accesso: un token in un URL è un token in un file di log.
Quanto può essere lungo un URL prima che qualcosa lo tronchi?
Nessuna specifica fissa un limite; ogni implementazione fissa il proprio, e quello che morde per primo di solito non è il browser. La RFC 3986 rifiuta esplicitamente di imporre un massimo e raccomanda invece che tutto ciò che manipola URL regga lunghezze superiori a quelle che si aspetta. In pratica i browser accettano decine di migliaia di caratteri, mentre server web e proxy rifiutano comunemente una riga di richiesta oltre circa 8 kilobyte e rispondono con uno stato 414. Gli strumenti di analisi e di risultati di ricerca troncano molto prima. Il consiglio pratico non dipende da alcuna cifra esatta: se la tua query string arriva alle migliaia di caratteri, i dati vanno in un corpo POST o dietro un identificatore breve, non in un link. Gli URL lunghi si rompono anche quando vengono incollati in client di posta e app di messaggistica, che li mandano a capo a una colonna e trasformano un link in due.

Articoli che potrebbero interessarti

Tutte le guide
SpiegazioneCos'è un codice QR?Un codice QR è un codice a barre 2D che una fotocamera legge per aprire un link o testo. Ecco cos'è, perché contiene tanto, la sua anatomia e una nota di sicurezza.SpiegazioneCos'è un'espressione cron?Un'espressione cron pianifica l'esecuzione automatica di un'attività a orari fissati. Ecco a cosa serve, i suoi cinque campi, come leggerla, e i tranelli comuni.GuidaLa codifica URL spiegata: percent-encoding e dove mordeIl percent-encoding si decide componente per componente, ed è da lì che nasce tutta la confusione. Una barra è lecita in un percorso e va escapata in un valore di query; uno spazio è %20 in un percorso e può essere + in un corpo di form. Ecco gli insiemi esatti della RFC 3986, le tre funzioni JavaScript che non concordano e le trappole.SpiegazioneEstrarre tutti gli indirizzi email o URL da un blocco di testoUn URL a fine frase si tiene il punto; un indirizzo email a fine della stessa frase no. Un nome accentato dentro un indirizzo torna troncato. Ogni caso qui è stato passato negli strumenti e l'output esatto è riportato.SpiegazioneChe cosa c'è dentro un JWT — e che cosa non proteggeUn JWT è firmato, non cifrato. Chiunque abbia il token può decodificare il payload e leggerne ogni claim. Ecco un token reale, decodificato senza alcuna chiave, più i tre attacchi che la firma deve fermare e l'unico problema che non può risolvere.ConfrontoJSON vs XML: qual è la differenza?JSON e XML memorizzano entrambi dati strutturati come testo, ma con compromessi diversi. Ecco come appare ciascuno, dove vince ciascuno e come scegliere.

Strumenti correlati

Queste cifre vengono dall'aver eseguito questi strumenti su file veri e compresso il risultato, non da una promessa di un fornitore. Il peso dipende interamente dal file: un foglio di stile scritto con commenti lunghi non si comprime come uno senza, e i tuoi numeri non saranno i nostri. Nemmeno i minificatori si equivalgono — due di questo sito divergono sullo stesso input — quindi tratta qualsiasi output minificato come codice nuovo, da rileggere prima di pubblicare. Tieni l'originale leggibile nel controllo di versione, minifica in fase di build e controlla la pagina in un browser prima di pubblicare.

Fonti

Hai notato un errore in questo articolo?