Qu'est-ce que l'encodage pour cent ? (Le RFC 3986 expliqué simplement)
L'encodage pour cent est un mécanisme défini dans le RFC 3986 permettant d'encoder les caractères spéciaux dans les URI en les remplaçant par un signe pour cent (%) suivi de deux chiffres hexadécimaux. Il garantit que les URL ne contiennent que des caractères ASCII valides pouvant être transmis en toute sécurité sur Internet.
Qu'est-ce que l'encodage pour cent ?
L'encodage pour cent, également appelé encodage d'URL, est la méthode standard pour représenter dans un URI (Uniform Resource Identifier) les caractères qui ne sont pas autorisés ou qui ont une signification particulière. Il fonctionne en remplaçant chaque caractère à encoder par un signe pour cent (%) suivi de deux chiffres hexadécimaux représentant la valeur d'octet du caractère.
Par exemple, le caractère espace (valeur d'octet 0x20) est encodé en %20. L'arobase @ (valeur d'octet 0x40) est encodée en %40. Ce mécanisme garantit que n'importe quelle donnée peut être intégrée en toute sécurité dans un URI sans entrer en conflit avec la syntaxe de l'URI.
Le terme « encodage pour cent » vient de l'utilisation du caractère pour cent comme préfixe d'échappement. La spécification formelle est définie dans le RFC 3986, publié par l'Internet Engineering Task Force (IETF) en janvier 2005 et rédigé par Tim Berners-Lee, Roy Fielding et Larry Masinter.
Comment fonctionne l'encodage pour cent
Le processus d'encodage suit ces étapes : d'abord, le caractère est converti en sa représentation en octets à l'aide d'un encodage de caractères (presque toujours UTF-8 sur le web moderne). Ensuite, chaque octet est représenté par un signe pour cent suivi de deux chiffres hexadécimaux (en majuscules A-F par convention, même si les décodeurs doivent accepter les minuscules).
// Encodage étape par étape d'un caractère espace
// Caractère : ' ' (espace)
// Valeur d'octet ASCII/UTF-8 : 0x20 (32 en décimal)
// Encodé pour cent : %20
// Encodage étape par étape d'un caractère multi-octets : e accent aigu
// Caractère : e accent aigu (U+00E9)
// Octets UTF-8 : 0xC3 0xA9
// Encodé pour cent : %C3%A9
// Encodage étape par étape d'un caractère sur 3 octets
// Caractère : idéogramme CJK (U+4E2D)
// Octets UTF-8 : 0xE4 0xB8 0xAD
// Encodé pour cent : %E4%B8%AD
Les chiffres hexadécimaux doivent toujours venir par paires. Un signe pour cent isolé, ou suivi de caractères non hexadécimaux, est invalide et provoquera une erreur de décodage. C'est une cause fréquente de l'erreur « URI malformed » en JavaScript.
L'encodage pour cent est toujours réversible. Le décodeur lit le signe pour cent, prend les deux caractères suivants comme valeur d'octet hexadécimale et la reconvertit en caractère d'origine. Pour les caractères UTF-8 multi-octets, les octets encodés consécutifs sont combinés et décodés ensemble.
Quels caractères doivent être encodés ?
Tous les caractères n'ont pas besoin d'un encodage pour cent. Le RFC 3986 définit deux catégories : les caractères non réservés qui n'ont jamais besoin d'être encodés, et les caractères réservés qui doivent être encodés lorsqu'ils ne sont pas utilisés dans leur rôle réservé. 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ères qui n'ont PAS besoin d'être encodés (non réservés) : lettres majuscules (A-Z), lettres minuscules (a-z), chiffres (0-9), tiret (-), point (.), tiret bas (_) et tilde (~). Ces 66 caractères peuvent apparaître n'importe où dans un URI sans encodage.
Caractères qui ont parfois besoin d'être encodés (réservés) : : / ? # [ ] @ ! $ & ' ( ) * + , ; =. Ces caractères ont une signification syntaxique particulière dans les URI. Ils n'ont besoin d'être encodés que lorsqu'ils sont utilisés comme données plutôt que comme délimiteurs.
Caractères qui ont toujours besoin d'être encodés : les espaces, les caractères non-ASCII (tout caractère au-delà de 127), les caractères de contrôle (0-31 et 127) et les caractères dangereux comme < > { } | \ ^ ` ".
Caractères réservés et non réservés dans le RFC 3986
La distinction entre caractères réservés et non réservés est fondamentale pour comprendre le fonctionnement des URI. Les caractères réservés servent de délimiteurs qui définissent la structure d'un URI. Par exemple, :// sépare le schéma de l'autorité, / sépare les segments du chemin, ? marque le début de la chaîne de requête et # marque le début du fragment.
| Catégorie | Caractères | Quand encoder |
|---|---|---|
| Non réservés | A-Z a-z 0-9 - . _ ~ |
Jamais |
| Délimiteurs généraux | : / ? # [ ] @ |
Lorsqu'ils sont utilisés comme données, non comme délimiteurs |
| Sous-délimiteurs | ! $ & ' ( ) * + , ; = |
Lorsqu'ils sont utilisés comme données dans des composants qui leur donnent une signification |
| Tous les autres caractères | Espaces, non-ASCII, caractères de contrôle, etc. | Toujours |
Un principe essentiel du RFC 3986 est que deux URI qui ne diffèrent que par le fait qu'un caractère réservé soit encodé pour cent ou apparaisse littéralement ne sont pas équivalents. Par exemple, /path/to et /path%2Fto sont des URI différents, même si %2F se décode en /. Le premier comporte deux segments de chemin ; le second comporte un seul segment de chemin qui contient une barre oblique littérale.
Encodage pour cent et encodage d'URL : est-ce la même chose ?
« Encodage pour cent » et « encodage d'URL » sont souvent employés de manière interchangeable et, dans la plupart des contextes, ils désignent la même chose. Il existe cependant une subtile distinction historique. « Encodage d'URL » peut parfois désigner l'ancien format application/x-www-form-urlencoded utilisé par les formulaires HTML, qui encode les espaces en + au lieu de %20.
Le format application/x-www-form-urlencoded a été défini dans la spécification HTML et est antérieur au RFC 3986. Il obéit à des règles légèrement différentes : les espaces deviennent +, et l'ensemble des caractères qui ne sont pas encodés est légèrement différent. L'usage moderne du terme « encodage d'URL » fait presque toujours référence à l'encodage pour cent du RFC 3986, où les espaces sont représentés par %20.
En pratique, vous devriez utiliser l'encodage pour cent du RFC 3986 pour tous les contextes d'URI (segments de chemin, paramètres de requête dans les API REST, identifiants de fragment). N'utilisez le format application/x-www-form-urlencoded que pour les soumissions de formulaires HTML ou lorsqu'une API spécifique l'exige.
// Encodage pour cent RFC 3986 (recommandé pour les URI)
encodeURIComponent('hello world') // "hello%20world"
// application/x-www-form-urlencoded (formulaires HTML)
new URLSearchParams({q: 'hello world'}).toString() // "q=hello+world"
// Équivalent en Python
from urllib.parse import quote, quote_plus
quote('hello world', safe='') # "hello%20world"
quote_plus('hello world') # "hello+world"