823 votes

Encodage d'URL Java des paramètres de chaîne de requête

Dire que j'ai une URL

http://example.com/query?q=

et j'ai une requête entrée par l'utilisateur telle que :

mot aléatoire £500 banque $

Je veux que le résultat soit une URL correctement encodée :

http://example.com/query?q=random%20word%20%A3500%20bank%20%24

Quelle est la meilleure façon d'atteindre cela ? J'ai essayé URLEncoder et la création des objets URI/URL mais aucun d'entre eux ne fonctionne tout à fait correctement.

30 votes

Que voulez-vous dire par "aucun d'eux ne sort bien" ?

2 votes

J'ai utilisé URI.create et j'ai remplacé les espaces par + dans la chaîne de requête. Sur le site du client, les + ont été convertis en espaces lorsque j'ai sélectionné les chaînes de requête. Cela a fonctionné pour moi.

1332voto

BalusC Points 498232

URLEncoder est la voie à suivre. Vous devez simplement vous rappeler d'encoder seulement le nom du paramètre de requête individuel et/ou sa valeur, pas l'URL entière, certainement pas le caractère séparateur des paramètres de requête & ni le caractère séparateur du nom de paramètre-valeur =.

String q = "random word £500 bank $";
String url = "https://example.com?q=" + URLEncoder.encode(q, StandardCharsets.UTF_8);

Si vous n'êtes toujours pas sur Java 10 ou plus récent, alors utilisez StandardCharsets.UTF_8.toString() comme argument de jeu de caractères, ou si vous n'êtes toujours pas sur Java 7 ou plus récent, alors utilisez "UTF-8".


Remarquez que les espaces dans les paramètres de requête sont représentés par +, pas par %20, ce qui est parfaitement valide. Le %20 est généralement utilisé pour représenter les espaces dans l'URI lui-même (la partie avant le caractère séparateur de chaîne de requête d'URI ?), pas dans la chaîne de requête (la partie après ?).

Remarquez également qu'il y a trois méthodes encode(). Une sans Charset en tant que deuxième argument et une autre avec String comme deuxième argument qui lance une exception vérifiée. Celle sans argument Charset est obsolète. Ne l'utilisez jamais et spécifiez toujours l'argument Charset. Même la javadoc recommande explicitement d'utiliser l'encodage UTF-8, tel que prescrit par RFC3986 et W3C.

Tous les autres caractères sont considérés comme non sécurisés et sont d'abord convertis en un ou plusieurs octets en utilisant un certain schéma d'encodage. Ensuite, chaque octet est représenté par la chaîne de 3 caractères "%xy", où xy est la représentation hexadécimale à deux chiffres de l'octet. Le schéma d'encodage recommandé à utiliser est UTF-8. Cependant, pour des raisons de compatibilité, si un codage n'est pas spécifié, alors le codage par défaut de la plate-forme est utilisé.

Voir aussi :

1 votes

Il peut y avoir 2 types de paramètres dans l'URL. Chaîne de requête (suivie de ?) et paramètre de chemin (typiquement partie de l'URL elle-même). Alors, qu'en est-il des paramètres de chemin. URLEncoder produit + pour l'espace même pour les paramètres de chemin. En fait, il ne gère rien d'autre que la chaîne de requête. De plus, ce comportement n'est pas synchronisé avec les serveurs node js. Donc pour moi cette classe est une perte de temps et ne peut pas être utilisée autrement que pour des scénarios très spécifiques / spéciaux.

8 votes

@sharadendusinha : Comme documenté et expliqué, URLEncoder est destiné aux paramètres de requête encodés dans l'URL conformément aux règles application/x-www-form-urlencoded. Les paramètres de chemin ne rentrent pas dans cette catégorie. Vous avez besoin d'un encodeur d'URI à la place.

2 votes

Comme je l'avais prédit ... les utilisateurs sont confus car évidemment le problème est que les gens doivent encoder plus que simplement la valeur du paramètre. C'est un cas très rare où vous avez seulement besoin d'encoder une valeur de paramètre. C'est pourquoi j'ai fourni ma réponse wiki "confused" pour aider des personnes comme @sharadendusinha.

200voto

Adam Gent Points 15055

Je n'utiliserais pas URLEncoder. En plus d'être mal nommé (URLEncoder n'a rien à voir avec les URL), inefficace (il utilise un StringBuffer au lieu de Builder et fait quelques autres choses qui sont lentes) Il est aussi trop facile de faire des erreurs.

À la place, j'utiliserais URIBuilder ou Spring's org.springframework.web.util.UriUtils.encodeQuery ou Commons Apache HttpClient. La raison en est que vous devez échapper les noms des paramètres de la requête (c.-à-d. la réponse de BalusC q) différemment de la valeur du paramètre.

Le seul inconvénient de ce qui précède (que j'ai découvert douloureusement) est que les URL ne sont pas un vrai sous-ensemble des URI.

Code d'exemple:

import org.apache.http.client.utils.URIBuilder;

URIBuilder ub = new URIBuilder("http://example.com/query");
ub.addParameter("q", "mot aléatoire £500 banque \$");
String url = ub.toString();

// Résultat: http://example.com/query?q=mot+al%C3%A9atoire+%C2%A3500+banque+%24

2 votes

Pourquoi cela n'a-t-il rien à voir avec les URL?

22 votes

@Luis: URLEncoder est, comme le dit son javadoc, destiné à encoder les paramètres de chaîne de requête conformément à application/x-www-form-urlencoded tel que décrit dans la spécification HTML : w3.org/TR/html4/interact/…. Certains utilisateurs le confondent / l'utilisent en abusant pour encoder des URI complets, comme l'a apparemment fait la personne qui a répondu précédemment.

9 votes

@LuisSep en bref, URLEncoder est pour l'encodage pour la soumission de formulaire. Ce n'est pas pour l'échappement. Ce n'est pas exactement le même échappement que vous utiliseriez pour créer des URL à mettre sur votre page web, mais il est suffisamment similaire pour que les gens en abusent. La seule fois où vous devriez utiliser URLEncoder est si vous écrivez un client HTTP (et même alors, il existe des options bien supérieures pour l'encodage).

115voto

M Abdul Sami Points 1

Vous devez d'abord créer une URI comme suit:

String urlStr = "http://www.example.com/CEREC® Materials & Accessories/IPS Empress® CAD.pdf"
URL url = new URL(urlStr);
URI uri = new URI(url.getProtocol(), url.getUserInfo(), url.getHost(), url.getPort(), url.getPath(), url.getQuery(), url.getRef());

Ensuite, convertissez cette URI en une chaîne ASCII:

urlStr = uri.toASCIIString();

Maintenant, votre chaîne d'URL est complètement encodée. Tout d'abord, nous avons effectué un simple encodage d'URL puis nous l'avons converti en une chaîne ASCII pour nous assurer qu'aucun caractère en dehors de l'US-ASCII ne restait dans la chaîne. C'est exactement ce que font les navigateurs.

8 votes

Merci! C'est stupide que votre solution fonctionne, mais la méthode intégrée URL.toURI() ne fonctionne pas.

2 votes

Malheureusement, cela ne semble pas fonctionner avec "file:///" (par exemple : "file:///some/directory/a file containing spaces.html") ; cela échoue avec une MalformedURLException dans "new URL()"; avez-vous une idée de comment résoudre cela ?

0 votes

Vous devez faire quelque chose comme ceci: String urlStr = "some/directory/a fichier contenant des espaces.html"; URL url= new URL(urlStr); URI uri = new URI(url.getProtocol(), url.getUserInfo(), url.getHost(), url.getPort(), url.getPath(), url.getQuery(), url.getRef()); urlStr=uri.toASCIIString(); urlStr.replace("http://","file:///"); Je ne l'ai pas testé, mais je pense que ça fonctionnera.... :)

37voto

Emmanuel Touzery Points 1677

2 votes

Ces souffrent des mêmes règles d'échappement ridicules que URLEncoder.

4 votes

Pas certain qu'ils aient le problème. ils différencient par exemple "+" ou "%20" pour échapper à " "(paramètre de formulaire ou paramètre de chemin) que URLEncoder ne le fait pas.

1 votes

Cela a fonctionné pour moi, j'ai simplement remplacé l'appel à URLEncoder() par un appel à UrlEscapers.urlFragmentEscaper() et cela a fonctionné. Il n'est pas clair si je devrais utiliser UrlEscapers.urlPathSegmentEscaper() à la place.

4voto

Pooja Kansal Points 6049

Il s'agit d'une solution supplémentaire et non particulière (qui a déjà été répondue). Si quelqu'un souhaite remplacer des symboles spécifiques ou des espaces blancs, il peut simplement utiliser ce qui suit :-

String strUrl = getResources().getString(R.string.ipaddress)
            + "/index.php?action=passengerRegistration&name=" + strname
            + "&gender=" + strgender + "&location=" + strLocation
            + "&phoneNo=" + strphoneno + "&password=" + strPwd + "&email="
            + stremail;

strRegUrl = strRegUrl.replaceAll(" ", "%20");

comme votre nom contient un espace blanc "hello name"

alors ce sera "hello%20name" ce qui ne posera pas de problème !

de même, nous pouvons cibler des symboles spécifiques aussi ! :)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X