Encodeur / décodeur d’URL

Encodez et décodez des URL, choisissez la portée composant ou URL complète, et décomposez une URL en ses parties.

Pour une valeur isolée, comme un paramètre de requête. Échappe aussi / ? : @ & = + car ce sont là des données, pas de la structure.

Entrée
Sortie

La sortie apparaîtra ici

À quoi sert l’encodage en pourcentage

Une URL ne peut contenir qu’un petit ensemble de caractères : les lettres A–Z et a–z, les chiffres, une poignée de signes comme - . _ ~, et un ensemble de caractères réservés qui donnent sa forme à l’adresse — / ? # & = : @ et quelques autres. Tout le reste, d’une espace à un mot en hébreu ou à un emoji, doit être représenté indirectement. L’encodage en pourcentage est cette représentation : le caractère est converti en ses octets UTF-8 et chaque octet s’écrit sous forme d’un signe pourcent suivi de deux chiffres hexadécimaux. Une espace devient %20, et א devient %D7%90.

Les caractères réservés sont le cas intéressant. Ils sont licites dans une URL, mais ils ont un sens structurel : ? ouvre la requête, & sépare les paramètres, = distingue une clé de sa valeur. Quand l’un d’eux fait partie de vos données plutôt que de la structure, il doit être encodé — sinon l’analyseur d’en face le lira comme de la ponctuation et coupera votre valeur au mauvais endroit.

Composant ou URL complète — la distinction qui casse les liens

C’est la source la plus fréquente de bugs d’URL, et c’est pourquoi cet outil vous demande de choisir une portée au lieu de deviner.

  • La portée composant échappe aussi les délimiteurs : / ? : @ & = + $ , et #. Utilisez-la pour une seule donnée — un terme de recherche, une cible de redirection, un jeton — destinée à être insérée dans une URL plus grande.
  • La portée URL complète laisse ces délimiteurs intacts et n’échappe que ce qui est réellement illicite, comme les espaces et le texte non-ASCII. Utilisez-la quand vous avez une adresse complète déjà correctement structurée qui a simplement besoin d’être nettoyée.

Se tromper dans un sens ou dans l’autre casse quelque chose. Encodez une URL entière en portée composant et chaque barre oblique et point d’interrogation deviennent %2F et %3F, produisant une seule chaîne inutilisable. Encodez une valeur isolée en portée URL complète et une esperluette à l’intérieur survit comme délimiteur : une recherche de « chats & chiens » devient silencieusement deux paramètres et la seconde moitié de votre valeur disparaît.

// La valeur contient un délimiteur, elle doit donc être échappée :
const q = 'cats & dogs'
`/search?q=${encodeURIComponent(q)}`  // /search?q=cats%20%26%20dogs
`/search?q=${encodeURI(q)}`           // /search?q=cats%20&%20dogs  ✗

// Mieux encore : laissez la plateforme l’assembler
const url = new URL('https://example.com/search')
url.searchParams.set('q', 'cats & dogs')

Cette dernière approche mérite de devenir une habitude. URL et URLSearchParams sont intégrés à tous les navigateurs et à Node, et ils appliquent le bon encodage à chaque partie pour vous — ce qui supprime la décision au lieu de vous obliger à viser juste à la main chaque fois.

Pourquoi une espace est tantôt + tantôt %20

Deux spécifications différentes sont à l’œuvre, et elles divergent sur exactement un caractère. Le RFC 3986, qui régit les URL en général, encode une espace en %20. Le format plus ancien application/x-www-form-urlencoded, celui que soumettent les formulaires HTML et donc celui auquel ressemblent la plupart des chaînes de requête, l’encode en +.

Le piège, c’est que decodeURIComponent n’implémente que la première règle. Donnez-lui hello+world et vous récupérez hello+world, plus compris — aucune erreur, aucun avertissement, juste une valeur subtilement fausse. C’est pourquoi cet outil propose l’option « traiter + comme une espace » et vous la signale quand votre saisie contient un plus alors que l’option est désactivée.

Notez que URLSearchParams, qui alimente le tableau de décomposition sous l’outil, suit les règles des formulaires et convertit bien + en espace. La même chaîne de requête peut donc se décoder différemment selon l’API choisie — délibérément, et correctement, dans les deux cas.

Une conséquence à retenir : si un plus fait réellement partie de vos données — un numéro de téléphone, une expression de filtre — il doit être encodé en %2B. Un + littéral dans une chaîne de requête est ambigu au mieux et sera lu comme une espace par la plupart des analyseurs.

Lire une URL

Collez une URL absolue et l’outil la décompose en ses parties. Il vaut la peine de savoir comment chacune s’appelle, car les messages d’erreur et la documentation supposent ce vocabulaire :

  • Schéma — https, mailto, ftp. Tout ce qui précède les deux-points, et ce qui décide comment le reste est interprété.
  • Infos utilisateur — un user:password facultatif avant l’hôte. Toujours licite, et toujours une mauvaise idée : elles voyagent à chaque requête et atterrissent dans les journaux, l’historique du navigateur et les en-têtes referrer.
  • Hôte — le nom de domaine ou l’adresse IP. Tout ce qui suit est traité par ce serveur, pas par le réseau.
  • Port — généralement absent, car 443 pour https et 80 pour http sont implicites.
  • Origine — le schéma, l’hôte et le port réunis. C’est l’unité sur laquelle repose la sécurité du navigateur : la politique de même origine, CORS et la portée des cookies comparent des origines, pas des chemins.
  • Chemin — la partie après l’hôte et avant tout ? ou #.
  • Requête — les paires clé/valeur après le ?, séparées par des &.
  • Fragment — tout ce qui suit le #. Fait unique, il n’est jamais envoyé au serveur ; le navigateur le traite entièrement.

Ce détail sur le fragment compte plus qu’il n’y paraît. Comme il ne quitte jamais le navigateur, tout ce que vous placez après un # est invisible dans les journaux du serveur — d’où son usage historique pour le routage dans certaines applications monopages, et d’où le fait que ce n’est pas là qu’il faut chercher en déboguant une requête qui n’est jamais arrivée.

Une dernière mise en garde sur ce que l’encodage ne fait pas. L’encodage en pourcentage rend un texte transportable en toute sûreté dans une URL ; ce n’est ni un assainissement ni un contrôle de sécurité. Encoder une valeur ne la rend pas sûre à interpoler dans du HTML, du SQL ou une commande shell, et décoder une entrée non fiable peut révéler des caractères — séparateurs de chemin, octets nuls — que la forme encodée dissimulait. Validez ce qu’est une valeur, séparément de l’encodage de la façon dont elle voyage.

L’adresse saisie n’est pas toujours celle qui part

Avant qu’une URL n’aille où que ce soit, elle est normalisée, et la réécriture est silencieuse. Cet outil affiche le résultat dès qu’il diffère de la saisie, car c’est cette chaîne — et non celle que vous avez tapée — qui atteint le serveur et apparaît dans un journal :

HTTPS://Example.COM:443\a\b     saisi
https://example.com/a/b         envoye

Quatre règles distinctes se sont déclenchées ici. Le schéma et l’hôte passent en minuscules, puisque ni l’un ni l’autre n’est sensible à la casse. Le port disparaît parce que 443 est la valeur par défaut de https. Les antislashs deviennent des barres obliques, une règle de compatibilité qui surprend ceux qui écrivent des chemins à la mode Windows. Et un chemin vide serait devenu une simple barre. Rien de tout cela n’est une erreur, mais si vous comparez deux URL, ou si vous en confrontez une à une liste d’autorisation, vous devez comparer les formes normalisées sous peine d’obtenir une mauvaise réponse.

Un nom d’hôte comportant des caractères non ASCII est lui aussi réécrit, en une forme ASCII commençant par xn--, appelée punycode. L’outil montre les deux sens : le nom lisible et celui qui voyage réellement. Cela vaut la peine d’y regarder plutôt que de passer, car deux noms Unicode différents peuvent paraître identiques à l’écran — un « a » latin et un « а » cyrillique sont des caractères distincts — tout en produisant un punycode totalement différent. Comparer les formes ASCII est le seul moyen fiable de distinguer une telle paire.

Une chose n’est jamais normalisée : un paramètre de requête répété. Écrire ?tag=a&tag=b est parfaitement licite, et la norme ne dit pas ce que cela signifie : chaque pile a donc choisi sa propre réponse. PHP garde la dernière valeur, Express les rassemble en tableau, et beaucoup de cadriciels ainsi que URLSearchParams.get prennent la première. L’outil signale les clés répétées au lieu de les lister deux fois sans commentaire, car le bogue qui en découle — une valeur qui marche dans un service et disparaît dans un autre — est réellement difficile à repérer à la lecture.

Questions fréquentes

Quelle est la différence entre portée composant et URL complète ?
La portée composant échappe aussi les délimiteurs / ? : @ & = +, ce qui convient à une valeur isolée placée dans une URL. La portée URL complète les laisse intacts car ils y séparent les parties de l’adresse. Appliquer la portée composant à une URL entière transforme chaque barre oblique en %2F et produit une chaîne inutilisable.
Pourquoi mon texte décodé contient-il encore un + ?
Parce que decodeURIComponent suit le RFC 3986, où + n’est qu’un plus. Les envois de formulaire et la plupart des chaînes de requête utilisent l’encodage de formulaire, où + signifie une espace. Activez « traiter + comme une espace » quand le texte vient de l’un ou de l’autre.
Comment encoder un plus qui est vraiment un plus ?
Écrivez-le %2B. Un + littéral dans une chaîne de requête sera lu comme une espace par la plupart des analyseurs : tout plus qui fait réellement partie de vos données — dans un numéro de téléphone, par exemple — doit être échappé.
Faut-il encoder l’URL entière ou seulement les parties ?
Seulement les parties, et de préférence pas à la main : construisez l’adresse avec URL et URLSearchParams, qui appliquent le bon encodage à chaque composant. Encoder après coup une URL déjà assemblée est l’origine de la plupart des bugs de double encodage.
Pourquoi la décomposition affiche-t-elle une URL différente de celle que j’ai collée ?
Parce que c’est celle qui part. Une URL est normalisée avant usage : le schéma et l’hôte passent en minuscules, un port par défaut disparaît, les antislashs deviennent des barres obliques, un chemin vide devient une barre, et un hôte non ASCII devient du punycode. Si vous comparez des URL ou les confrontez à une liste d’autorisation, comparez ces formes normalisées plutôt que le texte brut.
Pourquoi aucune décomposition n’apparaît pour example.com/path ?
Parce que ce n’est pas une URL absolue : sans schéma, il n’y a pas d’hôte à identifier. L’outil n’en devine pas un pour vous : example.com:8080 est déjà une URL absolue valide dont le schéma est example.com et le chemin 8080, si bien qu’ajouter https:// en silence peut produire une décomposition qui paraît raisonnable et qui est fausse. Ajoutez vous-même le schéma et les parties apparaîtront.
Qu’est-ce que le double encodage ?
Encoder une valeur déjà encodée, si bien qu’un %20 devient %2520 — le signe pourcent lui-même est échappé. Cela se manifeste en général par des séquences %20 littérales visibles sur une page. Décodez une fois et vérifiez si vous voyez encore des séquences d’échappement ; si oui, c’était encodé deux fois.
Encoder une valeur la rend-il sûre ?
Non. L’encodage en pourcentage concerne le transport, pas la sûreté. Une valeur encodée reste ce qu’elle était, et elle a besoin de la même validation et du même échappement adapté au contexte avant d’atteindre HTML, SQL ou un shell.
Pourquoi le fragment n’est-il pas envoyé au serveur ?
Par conception : tout ce qui suit le # est traité par le seul navigateur et n’apparaît jamais dans la requête. C’est pourquoi il est invisible dans les journaux du serveur, et pourquoi il a historiquement servi au routage côté client.
Ce que je colle est-il envoyé quelque part ?
Non. L’encodage, le décodage et la décomposition de l’URL utilisent les fonctions intégrées du navigateur et s’exécutent entièrement sur votre appareil. Rien de ce que vous collez ne le quitte.