Guide de l'encodage URL : percent-encoding, RFC 3986 et erreurs courantes
Découvrez le fonctionnement de l'encodage URL, les caractères qui doivent être percent-encoded et les pièges fréquents. Couvre les règles RFC 3986, encodeURIComponent vs encodeURI, le double encodage et des exemples de programmation.
Guide de l'encodage URL : percent-encoding, RFC 3986 et erreurs courantes
Si vous avez déjà vu %20 dans une adresse web ou si vous vous êtes demandé pourquoi une requête API cassait lorsque vous ajoutiez un & dans un paramètre de requête, vous avez rencontré l'encodage URL. Aussi appelé percent-encoding, c'est le mécanisme qui permet d'inclure des caractères spéciaux dans les URL sans casser le web.
Ce guide couvre tout ce que les développeurs doivent savoir sur l'encodage URL : quels caractères doivent être encodés, comment l'algorithme fonctionne, les erreurs courantes qui cassent les applications et les fonctions d'encodage dans sept langages de programmation. Essayez notre encodeur et décodeur URL gratuit pour voir le percent-encoding en action.
Qu'est-ce que l'encodage URL ?
L'encodage URL (officiellement appelé percent-encoding dans RFC 3986) est le processus qui convertit les caractères dans un format pouvant être inclus en toute sécurité dans une URL. Les caractères qui ont une signification spéciale dans la syntaxe d'URL, ou qui se trouvent hors de la plage ASCII autorisée, sont remplacés par le signe % suivi de leur valeur hexadécimale sur deux chiffres.
Par exemple :
- Espace →
%20 - Esperluette
&→%26 - Égal
=→%3D - Slash
/→%2F - Signe euro
€→%E2%82%AC(trois octets UTF-8)
Pourquoi l'encodage URL est nécessaire
Les URL ont une syntaxe stricte définie dans RFC 3986. Certains caractères servent de délimiteurs structurels :
https://example.com:8080/path/to/page?key=value&other=data#section
___ ___________ ____ ___________ _____________________ _______
scheme host port path query string fragment
Chaque caractère délimiteur a un rôle défini :
| Caractère | Rôle dans l'URL | Ce qui arrive sans encodage |
|---|---|---|
: | Sépare le schéma de l'hôte, et l'hôte du port | key=time:30 embrouille les parseurs |
/ | Sépare les segments du chemin | /search/cats/dogs ressemble à 3 segments |
? | Démarre la chaîne de requête | ?query=what? a un sens ambigu |
# | Démarre l'identifiant de fragment | key=C# est tronqué à # |
& | Sépare les paramètres de requête | name=Tom&Jerry crée 2 paramètres |
= | Sépare la clé de la valeur | equation=2+2=4 contient 2 signes égal |
@ | Sépare userinfo de l'hôte | email=user@host ressemble à une authentification |
+ | Espace (uniquement en encodage de formulaire) | Ambigu : signe plus ou espace ? |
Lorsque ces caractères apparaissent comme données plutôt que comme délimiteurs, ils doivent être percent-encoded.
Quels caractères doivent être encodés ?
RFC 3986 classe les caractères en trois groupes :
Caractères non réservés (jamais besoin d'encodage)
Ces caractères peuvent apparaître partout dans une URL sans encodage :
A-Z a-z 0-9 - _ . ~
Total : 66 caractères.
Caractères réservés (à encoder lorsqu'ils sont des données)
Ces caractères ont une signification spéciale dans la syntaxe URL. Ils doivent être encodés lorsqu'ils sont utilisés comme valeurs de données :
| Caractère | Code hex | Rôle |
|---|---|---|
: | %3A | Séparateur schéma/port |
/ | %2F | Séparateur de chemin |
? | %3F | Début de requête |
# | %23 | Début de fragment |
[ | %5B | Crochets IPv6 |
] | %5D | Crochets IPv6 |
@ | %40 | Séparateur userinfo |
! | %21 | Sous-délimiteur |
$ | %24 | Sous-délimiteur |
& | %26 | Séparateur de paramètres |
' | %27 | Sous-délimiteur |
( | %28 | Sous-délimiteur |
) | %29 | Sous-délimiteur |
* | %2A | Sous-délimiteur |
+ | %2B | Sous-délimiteur / espace |
, | %2C | Sous-délimiteur |
; | %3B | Sous-délimiteur |
= | %3D | Séparateur clé-valeur |
Tout le reste (toujours encoder)
Tous les autres caractères, y compris les espaces, les caractères non ASCII et les caractères de contrôle, doivent toujours être encodés :
| Caractère | Encodage | Notes |
|---|---|---|
| Espace | %20 | Encodage le plus courant |
" | %22 | Guillemet double |
< | %3C | Inférieur à |
> | %3E | Supérieur à |
{ | %7B | Accolade gauche |
} | %7D | Accolade droite |
| ` | ` | %7C |
\ | %5C | Backslash |
^ | %5E | Accent circonflexe |
` | %60 | Backtick |
| Non ASCII | Multioctet | Encodé en UTF-8, puis percent-encoded |
Comment fonctionne le percent-encoding
L'algorithme d'encodage est simple :
- Vérifier si le caractère doit être encodé (non non-réservé, ou caractère réservé utilisé comme donnée)
- Convertir le caractère en sa séquence d'octets UTF-8
- Exprimer chaque octet sous la forme
%XX, où XX est la valeur hexadécimale
Exemple : encoder "café"
| Caractère | Octets UTF-8 | Percent-encoded |
|---|---|---|
| c | 63 | c (non réservé) |
| a | 61 | a (non réservé) |
| f | 66 | f (non réservé) |
| é | C3 A9 | %C3%A9 |
Résultat : caf%C3%A9
Exemple : encoder une chaîne de requête complète
URL d'origine :
https://example.com/search?q=hello world&lang=en&tag=c#
Correctement encodée :
https://example.com/search?q=hello%20world&lang=en&tag=c%23
Note : & et = restent non encodés car ils jouent leur rôle structurel. Seules les valeurs de données (hello world, c#) sont encodées.
Espaces : %20 ou + (signe plus)
Les deux encodages des espaces créent une confusion constante :
| Format | Encodage de l'espace | Standard | Où il est utilisé |
|---|---|---|---|
| Percent-encoding | %20 | RFC 3986 | Chemins d'URL, usage général |
| Encodage de formulaire | + | Spécification HTML (application/x-www-form-urlencoded) | Soumissions de formulaires HTML |
Bonne pratique : utilisez %20 pour les espaces dans les chemins d'URL. Dans les chaînes de requête, %20 et + sont largement acceptés, mais %20 est plus universellement compatible.
encodeURI vs encodeURIComponent
JavaScript fournit deux fonctions d'encodage URL au comportement très différent :
encodeURI()
Encode un URI complet. Préserve les caractères qui ont une signification structurelle dans les URL :
encodeURI("https://example.com/path with spaces?q=hello world")
// "https://example.com/path%20with%20spaces?q=hello%20world"
N'encode PAS : ; , / ? : @ & = + $ - _ . ! ~ * ' ( ) #
encodeURIComponent()
Encode un composant d'URI (par exemple une seule valeur de paramètre de requête). Encode tout sauf les caractères non réservés :
encodeURIComponent("hello world & goodbye")
// "hello%20world%20%26%20goodbye"
N'encode PAS : A-Z a-z 0-9 - _ . ! ~ * ' ( )
Quand utiliser lequel
| Scénario | Fonction | Exemple |
|---|---|---|
| Encoder une URL complète | encodeURI() | encodeURI(fullUrl) |
| Encoder une valeur de paramètre de requête | encodeURIComponent() | ?q=${encodeURIComponent(searchTerm)} |
| Encoder un segment de chemin | encodeURIComponent() | /users/${encodeURIComponent(username)} |
| Encoder une URL de redirection comme paramètre | encodeURIComponent() | ?redirect=${encodeURIComponent(returnUrl)} |
Règle pratique : si la valeur peut contenir &, =, ? ou /, utilisez encodeURIComponent().
Erreurs courantes
1. Double encodage
Le bug d'encodage URL le plus fréquent. Il arrive lorsque vous encodez une chaîne déjà encodée :
Original: hello world
First encode: hello%20world
Double encode: hello%2520world ← WRONG
Le % dans %20 est encodé en %25, produisant %2520. Le serveur reçoit le texte littéral %20 au lieu d'un espace.
Comment l'éviter : décodez toujours avant de réencoder, ou suivez explicitement si une chaîne est déjà encodée.
2. Ne pas encoder les valeurs de paramètres de requête
// WRONG - breaks if searchTerm contains & or =
const url = `/search?q=${searchTerm}`;
// CORRECT
const url = `/search?q=${encodeURIComponent(searchTerm)}`;
Si searchTerm vaut "cats & dogs", la mauvaise version crée /search?q=cats & dogs, qui se divise en deux paramètres : q=cats et dogs (voire pire).
3. Utiliser encodeURI() pour des valeurs de paramètres
// WRONG - encodeURI preserves & and =
const url = `/api?data=${encodeURI("a=1&b=2")}`;
// Result: /api?data=a=1&b=2 ← 3 parameters instead of 1
// CORRECT
const url = `/api?data=${encodeURIComponent("a=1&b=2")}`;
// Result: /api?data=a%3D1%26b%3D2 ← 1 parameter
4. Oublier les caractères non ASCII
Les URL contenant des caractères non ASCII (lettres accentuées, CJK, emoji) doivent être encodées :
❌ https://example.com/café
✅ https://example.com/caf%C3%A9
Les navigateurs modernes affichent la version décodée dans la barre d'adresse, mais la requête HTTP réelle utilise le percent-encoding.
Encodage URL dans les langages de programmation
| Langage | Encoder | Décoder |
|---|---|---|
| JavaScript | encodeURIComponent(str) | decodeURIComponent(str) |
| Python | urllib.parse.quote(str) | urllib.parse.unquote(str) |
| Java | URLEncoder.encode(str, "UTF-8") | URLDecoder.decode(str, "UTF-8") |
| PHP | rawurlencode($str) | rawurldecode($str) |
| C# | Uri.EscapeDataString(str) | Uri.UnescapeDataString(str) |
| Go | url.QueryEscape(str) | url.QueryUnescape(str) |
| Ruby | CGI.escape(str) | CGI.unescape(str) |
Note : URLEncoder.encode() en Java et urlencode() en PHP utilisent + pour les espaces (encodage de formulaire). Utilisez rawurlencode() en PHP pour respecter RFC 3986 avec %20 pour les espaces.
Encodage URL ou encodage HTML
Ces deux systèmes d'encodage sont souvent confondus :
| Fonction | Encodage URL | Encodage HTML |
|---|---|---|
| Objectif | Caractères sûrs dans les URL | Caractères sûrs dans HTML |
| Format | %XX (octets hex) | &name; ou &#number; |
| Espace | %20 | ou simple espace |
& | %26 | & |
< | %3C | < |
" | %22 | " |
| Standard | RFC 3986 | Spécification HTML |
| Utilisé pour | Chaînes de requête URL, chemins | Attributs HTML, contenu |
Ils servent des objectifs complètement différents et ne sont pas interchangeables.
Foire aux questions
Que signifie %20 dans une URL ?
%20 est la représentation percent-encoded d'un caractère espace. Le % indique l'encodage, et 20 est la valeur hexadécimale du caractère espace (32 en décimal). Lorsqu'un navigateur ou un serveur rencontre %20 dans une URL, il le remplace par un espace.
L'encodage URL est-il sensible à la casse ?
Les chiffres hexadécimaux dans le percent-encoding (%3A vs %3a) ne sont pas sensibles à la casse selon RFC 3986, mais le standard recommande les majuscules. La plupart des implémentations acceptent les deux. En revanche, le reste du chemin d'URL peut être sensible à la casse selon le serveur (les serveurs Linux le sont généralement, les serveurs Windows ne le sont pas).
Comment fonctionnent les noms de domaine internationaux ?
Les noms de domaine internationaux (IDN) utilisent un système appelé Punycode pour convertir les noms Unicode en ASCII. Par exemple, münchen.de devient xn--mnchen-3ya.de. Les composants de chemin et de requête utilisent le percent-encoding standard pour les caractères non ASCII.
Prêt à encoder ou décoder des URL ? Essayez notre encodeur et décodeur URL pour un percent-encoding instantané avec décomposition des caractères. Pour d'autres outils d'encodage, consultez notre encodeur Base64 et notre convertisseur hexadécimal vers texte.