Skip to content
Torna al blog
Tutorial

Codifica e decodifica URL: guida online alla codifica percentuale

Regole RFC 3986, encodeURI vs encodeURIComponent, mappatura byte UTF-8 ed esempi di codice in JS, Python, Go e Java. Prova il nostro strumento online gratuito.

12 min di lettura

Codifica e decodifica URL: guida per sviluppatori alla codifica percentuale

Stai facendo tail di un log del server e noti questo in una query string: %E4%BD%A0%E5%A5%BD. Sono dati corrotti? Un bug? Nessuno dei due — sono i caratteri cinesi 你好, convertiti in tre byte UTF-8 ciascuno, poi codificati in percentuale in un formato URL-safe. Ogni sviluppatore web prima o poi sbatte contro questo muro: qualcosa sembra rotto, ma l’URL funziona esattamente come progettato.

La codifica URL — formalmente chiamata codifica percentuale — è il meccanismo che rende sicuri i caratteri speciali per gli URL. Questa guida copre come funziona a livello di byte, quando ricorrere a encodeURI rispetto a encodeURIComponent, come codificare correttamente in quattro linguaggi e quali bug fanno inciampare anche gli sviluppatori esperti.

Incolla qualsiasi URL nel nostro Codificatore e decodificatore URL per vedere codifica e decodifica in tempo reale mentre segui.

Cos’è la codifica URL (codifica percentuale)?

Un URL può contenere solo un piccolo sottoinsieme di caratteri ASCII. Lettere, cifre e una manciata di simboli viaggiano per internet senza problemi. Tutto il resto — spazi, e commerciali, testo cinese, emoji — deve essere convertito in un formato che gli URL possano trasportare.

La codifica percentuale sostituisce ogni byte non sicuro con un segno % seguito da due cifre esadecimali. Uno spazio diventa %20. Una e commerciale diventa %26. Il nome viene da quel prefisso %.

Le regole vivono in RFC 3986, pubblicato nel 2005 e ancora lo standard di riferimento. Ha sostituito RFC 2396 e ha stretto la definizione di quali caratteri sono sicuri, quali sono riservati e come va gestito il testo non-ASCII.

Esempi rapidi:

InputCodificatoPerché
hello worldhello%20worldLo spazio non è permesso negli URL
price=10&tax=2price%3D10%26tax%3D2= e & hanno significato strutturale
%E4%B8%ADNon-ASCII → byte UTF-8 → codificato in percentuale
🚀%F0%9F%9A%80Emoji → 4 byte UTF-8 → codificato in percentuale

Quali caratteri devono essere codificati?

RFC 3986 divide i caratteri in tre gruppi.

Caratteri non riservati (mai codificati)

Questi 66 caratteri passano così come sono in qualsiasi parte di un URL:

A-Z  a-z  0-9  -  .  _  ~

Lettere, cifre, trattino, punto, underscore, tilde. Questa è l’intera lista.

Caratteri riservati (dipendono dal contesto)

Questi caratteri servono come delimitatori strutturali negli URL:

CarattereRuolo nella struttura URL
:Separa lo schema dall’authority (https:)
/Separa segmenti del percorso
?Inizia la query string
#Inizia il fragment
&Separa parametri della query
=Separa chiave da valore del parametro
@Separa userinfo dall’host
+ ! $ ' ( ) * , ; [ ]Vari ruoli riservati

La regola: quando un carattere riservato serve al suo scopo strutturale, lascialo in pace. Quando appare come dato (dentro un valore di parametro, per esempio), codificalo.

Tutto il resto (sempre codificato)

Spazi, parentesi angolari, parentesi graffe, pipe, backslash e caratteri non-ASCII (cinese, arabo, emoji) devono essere codificati in percentuale.

Una piega: RFC 3986 codifica gli spazi come %20, ma le submission di form HTML usano +. Più su questo conflitto più avanti.

Come funziona davvero la codifica URL: la pipeline UTF-8

Per i caratteri ASCII, la codifica è semplice: cerca il valore byte in esadecimale, anteponi %. Uno spazio (valore byte 32, hex 20) diventa %20.

Per il testo non-ASCII, la codifica ha tre passi:

Passo 1 — Carattere a code point Unicode. Il carattere é mappa al code point U+00E9. L’emoji 🚀 mappa a U+1F680.

Passo 2 — Code point a byte UTF-8. UTF-8 usa da 1 a 4 byte a seconda del range del code point. é (U+00E9) diventa due byte: 0xC3 0xA9. L’emoji razzo (U+1F680) diventa quattro byte: 0xF0 0x9F 0x9A 0x80.

Passo 3 — Ogni byte a %XX. Ogni byte dal passo 2 ottiene la sua tripletta codificata in percentuale.

Ecco la pipeline completa per diversi tipi di carattere:

CarattereCode PointByte UTF-8CodificatoMoltiplicatore di dimensione
AU+004141A (non codificato)
spazioU+002020%20
éU+00E9C3 A9%C3%A9
U+4E2DE4 B8 AD%E4%B8%AD
🚀U+1F680F0 9F 9A 80%F0%9F%9A%8012×

Puoi verificarlo tu stesso in JavaScript:

const char = '中';
const encoded = encodeURIComponent(char);
console.log(encoded); // '%E4%B8%AD'

// Traccia i byte
const bytes = new TextEncoder().encode(char);
console.log([...bytes].map(b => '%' + b.toString(16).toUpperCase()).join(''));
// '%E4%B8%AD' — corrisponde

Questa espansione conta per i limiti di lunghezza degli URL. Un URL con 20 caratteri cinesi aggiunge 180 caratteri di testo codificato in percentuale.

encodeURI vs encodeURIComponent — Scegliere la funzione giusta

Queste due funzioni JavaScript vengono confuse di continuo. Sembrano simili ma codificano set di caratteri molto diversi.

encodeURI()encodeURIComponent()
ScopoCodificare un URL completoCodificare un singolo componente (chiave o valore di parametro)
Preserva: / ? # & = @ + $ ,Nessuno di questi
CodificaSpazi, non-ASCII, alcune punteggiatureTutto tranne A-Z a-z 0-9 - _ . ~ ! ' ( ) *
Usa quandoHai un URL completo con spazi o Unicode nel percorsoStai costruendo parametri di query da input utente

Un bug che finisce in produzione regolarmente:

// ❌ BUG: encodeURI NON codifica &
const search = 'Tom & Jerry';
const bad = `https://api.example.com/search?q=${encodeURI(search)}`;
// Risultato: https://api.example.com/search?q=Tom%20&%20Jerry
// La & spezza la query string — il server vede q=Tom%20 e un parametro separato %20Jerry

// ✅ FIX: encodeURIComponent codifica & come %26
const good = `https://api.example.com/search?q=${encodeURIComponent(search)}`;
// Risultato: https://api.example.com/search?q=Tom%20%26%20Jerry

Quando in dubbio, scegli encodeURIComponent(). È corretto per il 95% della costruzione URL nel mondo reale.

Prova entrambe le modalità fianco a fianco nel nostro strumento Codificatore URL →

Codifica URL in ogni linguaggio

JavaScript (Browser e Node.js)

// Codifica un valore di parametro
const value = encodeURIComponent('price >= 100 & currency = €');
// 'price%20%3E%3D%20100%20%26%20currency%20%3D%20%E2%82%AC'

// Decodifica
const original = decodeURIComponent(value);
// 'price >= 100 & currency = €'

// Approccio moderno: URLSearchParams gestisce la codifica automaticamente
const params = new URLSearchParams({ q: 'hello world', lang: '中文' });
console.log(params.toString());
// 'q=hello+world&lang=%E4%B8%AD%E6%96%87'
// Nota: URLSearchParams usa + per gli spazi (form encoding)

Python

from urllib.parse import quote, unquote, urlencode

# Codifica un segmento di percorso
quote('hello world/file name.txt', safe='/')
# 'hello%20world/file%20name.txt'

# Codifica parametri di query
urlencode({'q': '你好', 'page': '1'})
# 'q=%E4%BD%A0%E5%A5%BD&page=1'

# quote_plus usa + per gli spazi (form encoding)
from urllib.parse import quote_plus
quote_plus('hello world')  # 'hello+world'
quote('hello world')       # 'hello%20world'

Go

import "net/url"

// Codifica un valore di query (usa + per gli spazi)
url.QueryEscape("hello world & more")
// "hello+world+%26+more"

// Codifica un segmento di percorso (usa %20 per gli spazi)
url.PathEscape("hello world & more")
// "hello%20world%20&%20more"

// Costruisci un URL in modo sicuro con url.Values
params := url.Values{}
params.Set("q", "你好世界")
params.Set("page", "1")
fmt.Println(params.Encode())
// "page=1&q=%E4%BD%A0%E5%A5%BD%E4%B8%96%E7%95%8C"

Java

import java.net.URLEncoder;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;

// Codifica (usa + per gli spazi — Java segue il form encoding)
String encoded = URLEncoder.encode("hello world & more", StandardCharsets.UTF_8);
// "hello+world+%26+more"

// Per conformità RFC 3986, sostituisci + con %20
String rfc3986 = encoded.replace("+", "%20");
// "hello%20world%20%26%20more"

// Decodifica
String decoded = URLDecoder.decode(encoded, StandardCharsets.UTF_8);
// "hello world & more"

Go e Java per default usano il form encoding (spazi come +). Per output RFC 3986, fai post-processing del risultato per sostituire + con %20.

Cinque bug di codifica URL che rompono la produzione

1. Doppia codifica (%2520 invece di %20)

Codifichi una stringa. Un framework la codifica di nuovo. Il % in %20 diventa %25, e il server vede testo letterale %20 invece di uno spazio.

Sintomo: gli URL contengono %2520, %253D o altri pattern %25xx.

Diagnosi: %25 in un URL significa che un carattere % è stato codificato, il che di solito indica doppia codifica.

Soluzione: decodifica prima, poi codifica una volta. Verifica se l’input è già codificato prima di codificarlo.

// Rileva doppia codifica
function isDoubleEncoded(str) {
  return /%25[0-9A-Fa-f]{2}/.test(str);
}

// Codifica sicura: decodifica prima, poi codifica
function safeEncode(str) {
  try { str = decodeURIComponent(str); } catch (e) { /* non codificato, va bene */ }
  return encodeURIComponent(str);
}

2. + nei segmenti di percorso

Uno sviluppatore codifica in URL un nome file usando una libreria che produce + per gli spazi. Il file my report.pdf diventa my+report.pdf. Il server tratta + come un segno più letterale e restituisce un 404.

La regola: + significa spazio solo nelle query string (dopo ?). Nei segmenti di percorso, + è solo +. Usa sempre %20 per gli spazi nei percorsi.

3. Redirect URI OAuth rotti

L’URL di autorizzazione si presenta così:

https://auth.provider.com/authorize?redirect_uri=https://myapp.com/callback?code=abc&state=xyz

Il server OAuth legge redirect_uri=https://myapp.com/callback?code=abc e tratta state=xyz come un parametro separato di livello superiore. L’autenticazione fallisce.

Soluzione: codifica l’intero valore del redirect URI:

const redirectUri = 'https://myapp.com/callback?code=abc&state=xyz';
const authUrl = `https://auth.provider.com/authorize?redirect_uri=${encodeURIComponent(redirectUri)}`;
// redirect_uri=https%3A%2F%2Fmyapp.com%2Fcallback%3Fcode%3Dabc%26state%3Dxyz

4. Testo non-ASCII illeggibile nei log

I log del server mostrano %E4%BD%A0%E5%A5%BD invece di caratteri cinesi leggibili. L’URL è codificato correttamente; il tuo visualizzatore di log semplicemente non sta decodificando le sequenze codificate in percentuale.

Soluzione: passa i log attraverso un decodificatore, o incolla l’URL in un Decodificatore URL per leggere il testo originale.

5. Fallimenti di firma API

OAuth 1.0 e AWS Signature V4 richiedono codifica RFC 3986 stretta. La encodeURIComponent() di JavaScript non codifica !, ', (, ), o *. Se questi caratteri appaiono nel tuo input di firma, la firma non corrisponderà.

Soluzione: fai post-processing dell’output:

function rfc3986Encode(str) {
  return encodeURIComponent(str).replace(/[!'()*]/g, c =>
    '%' + c.charCodeAt(0).toString(16).toUpperCase()
  );
}

%20 vs + — Il dilemma della codifica degli spazi

Due standard non sono d’accordo su come codificare un carattere.

StandardLo spazio diventaDove si applica
RFC 3986 (sintassi URI)%20Ovunque in un URL
application/x-www-form-urlencoded+Query string da submission di form HTML

La convenzione + è un retaggio dei primi browser web. Quando un <form> invia con method="GET", il browser codifica gli spazi come + nella query string. La specifica HTML codifica questo comportamento.

Il problema: + significa “spazio” solo nelle query string. Nei segmenti di percorso, un + è un segno più letterale. Per questo https://example.com/my+file.pdf serve un file chiamato my+file.pdf, non my file.pdf.

Linee guida pratiche:

  • Usa %20 quando costruisci URL manualmente o codifichi segmenti di percorso. Funziona ovunque.
  • Accetta + quando analizzi query string da submission di form — il tuo framework probabilmente già lo gestisce.
  • Non mescolarli. Scegli una convenzione per componente e attieniti a quella.

Codifica URL e sicurezza

La codifica URL NON è cifratura

La codifica percentuale è una trasformazione completamente reversibile e deterministica senza proprietà crittografiche. Chiunque può decodificare %48%65%6C%6C%6F di nuovo in Hello in millisecondi.

Non usare la codifica URL per nascondere dati sensibili. Usa HTTPS per cifrare l’intera richiesta. Gli URL appaiono nei log del server, nella cronologia del browser e negli header Referer, quindi le informazioni sensibili appartengono ai corpi delle richieste, non agli URL.

Attacchi di redirect aperti

Gli attaccanti usano URL codificati per bypassare validazioni ingenue. Un parametro di redirect che contiene %2F%2Fevil.com decodifica a //evil.com, che i browser trattano come URL relativo al protocollo che punta al dominio dell’attaccante.

Difesa: valida l’URL decodificato, non la forma codificata. Usa allowlist per i domini di redirect.

Exploit di doppia codifica

Un WAF controlla gli URL in arrivo per tag <script>. Un attaccante invia %253Cscript%253E. Il WAF vede testo codificato in percentuale e lo lascia passare. L’applicazione decodifica una volta in %3Cscript%3E, poi una seconda decodifica produce <script>, bypassando il filtro.

Difesa: normalizza tutto l’input (decodifica completamente) prima di applicare i controlli di sicurezza. Non affidarti a un singolo passaggio di decodifica.

Per più sui fondamentali di sicurezza web, vedi la nostra guida Web Security Essentials.

Limiti di lunghezza degli URL e quando la codifica diventa costosa

La specifica HTTP non fissa una lunghezza massima per gli URL, ma ogni livello dello stack impone limiti pratici.

LivelloLimite
Raccomandazione generale2.000 caratteri
Chrome, Firefox~2 MB (ma i server rifiutano molto prima)
Apache (default)8.190 byte
Nginx (default)8.192 byte
IIS16.384 byte (query string)
CDN, proxyVaria — spesso 4.096-8.192 byte

La codifica percentuale rende gli URL più lunghi. Un singolo carattere cinese passa da 1 carattere a 9 (%E4%B8%AD). Un’emoji si espande a 12. Duecento caratteri cinesi nella sola query string producono 1.800 caratteri di testo codificato in percentuale.

Quando raggiungi il limite: sposta i dati dai parametri di query al body di una richiesta POST. Per le interfacce di ricerca, un endpoint POST che accetta JSON funziona bene.

FAQ

Cos’è la codifica URL e perché gli sviluppatori ne hanno bisogno?

La codifica URL (codifica percentuale) converte i caratteri non permessi negli URL in sequenze esadecimali %XX. Gli URL supportano solo 66 caratteri ASCII non riservati. Spazi, e commerciali, testo Unicode e la maggior parte della punteggiatura devono essere codificati o romperanno la struttura dell’URL.

Qual è la differenza tra encodeURI e encodeURIComponent?

encodeURI() codifica un URL completo preservando i caratteri strutturali come ://, /, ? e &. encodeURIComponent() codifica tutto tranne A-Z a-z 0-9 - _ . ~ ! ' ( ) *. Usa encodeURIComponent() per i valori dei parametri di query. Usa encodeURI() solo quando hai un URL completo e vuoi correggere spazi o caratteri non-ASCII senza romperne la struttura.

Perché %20 a volte appare come + negli URL?

Entrambi rappresentano uno spazio, ma vengono da standard diversi. %20 segue RFC 3986 e funziona ovunque in un URL. + segue la specifica di codifica form HTML e funziona solo nelle query string. Nei segmenti di percorso, + è un segno più letterale. Usa %20 quando in dubbio.

Come faccio la codifica URL del testo in Python, JavaScript, Go e Java?

JavaScript: encodeURIComponent('hello world')hello%20world. Python: urllib.parse.quote('hello world')hello%20world. Go: url.QueryEscape("hello world")hello+world. Java: URLEncoder.encode("hello world", UTF_8)hello+world. Go e Java per default usano il form encoding (spazio come +) — sostituisci + con %20 per output RFC 3986.

La codifica URL può essere usata per sicurezza o cifratura?

No. La codifica URL è completamente reversibile senza alcuna chiave. Offre zero confidenzialità. Proteggi i dati sensibili con HTTPS, non con la codifica percentuale. Gli URL appaiono nei log del server, nella cronologia del browser e negli header Referer, quindi i dati sensibili appartengono ai corpi delle richieste.

Cos’è la doppia codifica e come la risolvo?

La doppia codifica accade quando una stringa già codificata viene codificata di nuovo. Il % in %20 viene codificato come %25, producendo %2520. I server vedono testo letterale %20 invece di uno spazio. Risolvi decodificando prima l’input, poi codificando una volta. Il pattern %25 seguito da due cifre esadecimali è il segnale rivelatore.

Qual è la lunghezza massima dell’URL?

Non esiste un massimo ufficiale nella specifica HTTP. 2.000 caratteri è il limite sicuro per ampia compatibilità. Apache per default 8.190 byte, Nginx 8.192 byte. I caratteri non-ASCII si espandono 3-12x quando codificati in percentuale, quindi gli URL internazionalizzati raggiungono i limiti più velocemente. Per payload di grandi dimensioni, passa a POST.

Articoli correlati

Vedi tutti gli articoli