web-dev-qa-db-fra.com

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

Dis 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 codée:

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

Quel est le meilleur moyen d'y parvenir? J'ai essayé URLEncoder et créé des objets URI/URL, mais aucun d'entre eux n'est parfaitement correct.

660
user1277546

URLEncoder devrait être la voie à suivre. Vous devez seulement garder à l’esprit que vous devez coder uniquement le nom et/ou la valeur du paramètre de chaîne de requête individuelle, et non l’URL complète. Évidemment, le caractère de séparation du paramètre de chaîne de requête & ne paramètre nom-valeur séparateur caractère =.

String q = "random Word £500 bank $";
String url = "http://example.com/query?q=" + URLEncoder.encode(q, "UTF-8");

Notez que les espaces dans les paramètres de requête sont représentés par +, pas %20, qui est légitimement valide. %20 doit généralement être utilisé pour représenter des espaces dans l'URI lui-même (la partie précédant 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 ?).

Notez également qu'il existe deux méthodes encode(). Un sans argument de jeu de caractères et un autre avec. Celui sans argument charset est obsolète. Ne l'utilisez jamais et spécifiez toujours l'argument charset. Le javadoc recommande même explicitement d'utiliser le codage UTF-8, comme prescrit par RFC3986 et W3C .

Tous les autres caractères sont dangereux et sont d'abord convertis en un ou plusieurs octets à l'aide d'un schéma de codage. 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 de codage recommandé est UTF-8 . Toutefois, pour des raisons de compatibilité, si aucun codage n'est spécifié, le codage par défaut de la plate-forme est utilisé.

Voir également:

1092
BalusC

Je n'utiliserais pas URLEncoder. En plus d'être nommé de manière incorrecte (URLEncoder n'a rien à voir avec les URL), il est inefficace (il utilise un StringBuffer à la place de Builder et effectue quelques autres opérations lentes). Il est également trop facile de le rater.

Au lieu de cela, je voudrais utiliser URIBuilder ou le org.springframework.web.util.UriUtils.encodeQuery de Spring ou Commons Apache HttpClient . La raison en est que vous devez échapper au nom des paramètres de requête (c'est-à-dire la réponse q de BalusC) différemment de la valeur du paramètre.

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

Exemple de code:

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

URIBuilder ub = new URIBuilder("http://example.com/query");
ub.addParameter("q", "random Word £500 bank \$");
String url = ub.toString();

// Result: http://example.com/query?q=random+Word+%C2%A3500+bank+%24

Depuis que je suis juste en train de faire un lien vers d'autres réponses, j'ai marqué ceci comme étant un wiki de communauté. N'hésitez pas à éditer.

157
Adam Gent

Vous devez d'abord créer un URI tel que:

    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());

Puis convertissez cet Uri en chaîne ASCII:

    urlStr=uri.toASCIIString();

Maintenant, votre chaîne d'URL est complètement encodée. Nous avons d'abord encodé l'URL, puis nous l'avons convertie en ASCII String afin de nous assurer qu'aucun caractère en dehors de US-ASCII ne reste dans la chaîne. C'est exactement ce que font les navigateurs.

92
M Abdul Sami

Guava 15 a maintenant ajouté n ensemble d’échappements d’URL simples .

34
Emmanuel Touzery

La bibliothèque de composants Apache Http fournit une option intéressante pour la construction et l’encodage de paramètres de requête -

Avec HttpComponents 4.x, utilisez - RLEncodedUtils

Pour HttpClient 3.x, utilisez - EncodingUtil

6
Sashi

Voici une méthode que vous pouvez utiliser dans votre code pour convertir une chaîne d'URL et une mappe de paramètres en une chaîne d'URL codée valide contenant les paramètres de requête.

String addQueryStringToUrlString(String url, final Map<Object, Object> parameters) throws UnsupportedEncodingException {
    if (parameters == null) {
        return url;
    }

    for (Map.Entry<Object, Object> parameter : parameters.entrySet()) {

        final String encodedKey = URLEncoder.encode(parameter.getKey().toString(), "UTF-8");
        final String encodedValue = URLEncoder.encode(parameter.getValue().toString(), "UTF-8");

        if (!url.contains("?")) {
            url += "?" + encodedKey + "=" + encodedValue;
        } else {
            url += "&" + encodedKey + "=" + encodedValue;
        }
    }

    return url;
}
5
Pellet

Utilisez la solution standard Java suivante (transmet environ 100 des cas de test fournis par Web Plattform Tests ):

0. Test si l'URL est déjà codée . Remplacez les espaces codés '+' par des espaces codés '% 20'.

1. Fractionner l'URL en éléments structurels. Utilisez Java.net.URL pour cela.

2. Encodez chaque pièce structurelle correctement!

3. Utilisez IDN.toASCII(putDomainNameHere) to Punycode pour encoder le nom de l'hôte!

4. Utilisez Java.net.URI.toASCIIString() pour coder en pourcentage, NFC codé en unicode le mieux serait NFKC!). Pour plus d'informations, voir: --- (Comment coder correctement cette URL

URL url= new URL("http://example.com/query?q=random Word £500 bank $");
URI uri = new URI(url.getProtocol(), url.getUserInfo(), IDN.toASCII(url.getHost()), url.getPort(), url.getPath(), url.getQuery(), url.getRef());
String correctEncodedURL=uri.toASCIIString(); 
System.out.println(correctEncodedURL);

Impressions

http://example.com/query?q=random%20Word%20%C2%A3500%20bank%20$

Voici quelques exemples qui fonctionneront également correctement

{
      "in" : "http://نامه‌ای.com/",
     "out" : "http://xn--mgba3gch31f.com/"
},{
     "in" : "http://www.example.com/‥/foo",
     "out" : "http://www.example.com/%E2%80%A5/foo"
},{
     "in" : "http://search.barnesandnoble.com/booksearch/first book.pdf", 
     "out" : "http://search.barnesandnoble.com/booksearch/first%20book.pdf"
}, {
     "in" : "http://example.com/query?q=random Word £500 bank $", 
     "out" : "http://example.com/query?q=random%20Word%20%C2%A3500%20bank%20$"
}
4
jschnasse

Dans mon cas, je devais simplement passer l’URL entière et ne coder que la valeur de chaque paramètre. Je n'ai pas trouvé de code commun pour le faire alors (!!), alors j'ai créé cette petite méthode pour faire le travail:

public static String encodeUrl(String url) throws Exception {
    if (url == null || !url.contains("?")) {
        return url;
    }

    List<String> list = new ArrayList<>();
    String rootUrl = url.split("\\?")[0] + "?";
    String paramsUrl = url.replace(rootUrl, "");
    List<String> paramsUrlList = Arrays.asList(paramsUrl.split("&"));
    for (String param : paramsUrlList) {
        if (param.contains("=")) {
            String key = param.split("=")[0];
            String value = param.replace(key + "=", "");
            list.add(key + "=" +  URLEncoder.encode(value, "UTF-8"));
        }
        else {
            list.add(param);
        }
    }

    return rootUrl + StringUtils.join(list, "&");
}

public static String decodeUrl(String url) throws Exception {
    return URLDecoder.decode(url, "UTF-8");
}

Il utilise org.Apache.commons.lang3.StringUtils

1
Laurent

Dans Android je voudrais utiliser ce code:

Uri myUI = Uri.parse ("http://example.com/query").buildUpon().appendQueryParameter("q","random Word A3500 bank 24").build();

Uri est un Android.net.Uri

0