Codage d'adresse URL HTTP en Java

366

Mon application autonome Java obtient une URL (qui pointe vers un fichier) de l'utilisateur et je dois la frapper et la télécharger. Le problème auquel je suis confronté est que je ne suis pas en mesure de coder correctement l'adresse URL HTTP ...

Exemple:

URL:  http://search.barnesandnoble.com/booksearch/first book.pdf

java.net.URLEncoder.encode(url.toString(), "ISO-8859-1");

me renvoie:

http%3A%2F%2Fsearch.barnesandnoble.com%2Fbooksearch%2Ffirst+book.pdf

Mais ce que je veux c'est

http://search.barnesandnoble.com/booksearch/first%20book.pdf

(espace remplacé par% 20)

Je suppose qu'il URLEncodern'est pas conçu pour encoder des URL HTTP ... Le JavaDoc dit "Classe utilitaire pour l'encodage de formulaires HTML" ... Y a-t-il une autre façon de le faire?

suDocker
la source
Le comportement est tout à fait correct. Le codage d'URL consiste à transformer quelque chose en une chaîne qui peut être transmise en toute sécurité en tant que paramètre d'URL et qui n'est pas du tout interprétée comme une URL. Alors que vous voulez qu'il convertisse simplement une petite partie de l'URL.
Stephen Holt

Réponses:

303

La classe java.net.URI peut vous aider; dans la documentation de l'URL que vous trouvez

Remarque, la classe URI effectue l'échappement de ses champs de composant dans certaines circonstances. La méthode recommandée pour gérer le codage et le décodage des URL consiste à utiliser un URI

Utilisez l'un des constructeurs avec plus d'un argument, comme:

URI uri = new URI(
    "http", 
    "search.barnesandnoble.com", 
    "/booksearch/first book.pdf",
    null);
URL url = uri.toURL();
//or String request = uri.toString();

(le constructeur à un seul argument de l'URI n'échappe PAS aux caractères illégaux)


Seuls les caractères illégaux sont échappés par le code ci-dessus - il n'échappe PAS aux caractères non ASCII (voir le commentaire de fatih).
La toASCIIStringméthode peut être utilisée pour obtenir une chaîne uniquement avec des caractères US-ASCII:

URI uri = new URI(
    "http", 
    "search.barnesandnoble.com", 
    "/booksearch/é",
    null);
String request = uri.toASCIIString();

Pour une URL avec une requête comme http://www.google.com/ig/api?weather=São Paulo, utilisez la version à 5 paramètres du constructeur:

URI uri = new URI(
        "http", 
        "www.google.com", 
        "/ig/api",
        "weather=São Paulo",
        null);
String request = uri.toASCIIString();
user85421
la source
13
Veuillez noter que la classe URI mentionnée ici provient de "org.apache.commons.httpclient.URI" et non de "java.net", l'URI "java.net" n'accepte pas les caractères illégaux, sauf si vous utiliserez constructeurs qui construisent l'URL à partir de ses composants, comme la manière mentionnée dans le commentaire de Matt ci
Mohamed Faramawi
7
@Mohamed: la classe que j'ai mentionnée et utilisée pour les tests est java.net.URI : elle fonctionnait parfaitement (Java 1.6). Je mentionnerais le nom de classe complet s'il n'était pas celui de Java standard et le lien pointe vers la documentation de java.net.URI. Et, par le commentaire de Sudhakar, cela a résolu le problème sans inclure de "bibliothèques communes"!
user85421
1
URI uri = new URI ("http", "search.barnesandnoble.com", "/ booksearch / é", null); Ne s'échappe pas correctement avec cet exemple? Cela aurait dû être échappé avec% échappements
fmucar
@fatih - c'est exact, merci! Normalement, cela ne devrait pas être un problème, mais il existe une solution simple - presque la même que celle que j'ai écrite auparavant. Voir 2e édition.
user85421
@Carlos Thx pour l'édition. Maintenant, il s'échappe mais ne s'échappe pas correctement. Il doit ajouter un% à la valeur HEX de char pour les paramètres de chemin, ce qui signifie que é char doit être converti en% e9
fmucar
91

Veuillez noter que la plupart des réponses ci-dessus sont incorrectes.

La URLEncoderclasse, malgré son nom, n'est PAS ce qui doit être ici. Il est malheureux que Sun ait nommé cette classe de façon si ennuyeuse. URLEncoderest destiné à transmettre des données en tant que paramètres, pas à encoder l'URL elle-même.

En d'autres termes, "http://search.barnesandnoble.com/booksearch/first book.pdf"c'est l'URL. Les paramètres seraient, par exemple "http://search.barnesandnoble.com/booksearch/first book.pdf?parameter1=this&param2=that",. Les paramètres sont ceux que vous utiliseriez URLEncoder.

Les deux exemples suivants mettent en évidence les différences entre les deux.

Ce qui suit produit les mauvais paramètres, selon la norme HTTP. Notez que l'esperluette (&) et le signe plus (+) ne sont pas encodés correctement.

uri = new URI("http", null, "www.google.com", 80, 
"/help/me/book name+me/", "MY CRZY QUERY! +&+ :)", null);

// URI: http://www.google.com:80/help/me/book%20name+me/?MY%20CRZY%20QUERY!%20+&+%20:)

Ce qui suit produira les paramètres corrects, avec la requête correctement encodée. Notez les espaces, les esperluettes et les marques plus.

uri = new URI("http", null, "www.google.com", 80, "/help/me/book name+me/", URLEncoder.encode("MY CRZY QUERY! +&+ :)", "UTF-8"), null);

// URI: http://www.google.com:80/help/me/book%20name+me/?MY+CRZY+QUERY%2521+%252B%2526%252B+%253A%2529
Mat
la source
2
C'est vrai, le constructeur URI code déjà la chaîne de requête, selon la documentation docs.oracle.com/javase/1.4.2/docs/api/java/net/… , java.lang.String, java.lang.String, int , java.lang.String, java.lang.String, java.lang.String)
madoke
8
@Draemon La réponse est correcte mais utilise la chaîne de requête d'une manière peu courante; un exemple plus normal pourrait être query = URLEncoder.encode(key) + "=" + URLEncoder.encode(value). Les documents indiquent simplement que "tout caractère qui n'est pas un caractère URI légal est cité".
tc.
1
Je suis d'accord avec Matt ici. Si vous tapez cette URL: " google.com/help/me/book name + me /? MY CRZY QUERY! + & + :)" dans un navigateur, il code automatiquement les espaces mais le "&" est utilisé comme valeur de requête le séparateur et le "+" sont perdus.
arcot
80

Je vais ajouter une suggestion ici destinée aux utilisateurs d'Android. Vous pouvez le faire, ce qui évite d'avoir à obtenir des bibliothèques externes. En outre, toutes les solutions de recherche / remplacement de caractères suggérées dans certaines des réponses ci-dessus sont périlleuses et doivent être évitées.

Essayez ceci:

String urlStr = "http://abc.dev.domain.com/0007AC/ads/800x480 15sec h.264.mp4";
URL url = new URL(urlStr);
URI uri = new URI(url.getProtocol(), url.getUserInfo(), url.getHost(), url.getPort(), url.getPath(), url.getQuery(), url.getRef());
url = uri.toURL();

Vous pouvez voir que dans cette URL particulière, j'ai besoin d'avoir ces espaces encodés afin de pouvoir l'utiliser pour une demande.

Cela profite de quelques fonctionnalités disponibles dans les classes Android. Tout d'abord, la classe URL peut décomposer une URL en ses composants appropriés, il n'est donc pas nécessaire que vous effectuiez un travail de recherche / remplacement de chaîne. Deuxièmement, cette approche tire parti de la fonctionnalité de classe URI consistant à échapper correctement les composants lorsque vous construisez un URI via des composants plutôt qu'à partir d'une seule chaîne.

La beauté de cette approche est que vous pouvez prendre n'importe quelle chaîne d'URL valide et la faire fonctionner sans avoir besoin de connaissances particulières vous-même.

Craig B
la source
3
Belle approche, mais je voudrais souligner que ce code n'empêche pas le double encodage , par exemple% 20 a été encodé en% 2520. La réponse de Scott n'en souffre pas.
nattster
2
Il ne peut pas gérer #.
Alston
Ou si vous voulez juste faire un chemin en citant: nouvel URI (null, null, "/ chemin avec des espaces", null, null) .toString ()
user1050755
1
@Stallman Si votre nom de fichier contient #, la classe URL le mettra dans "ref" (équivalent de "fragment" dans la classe URI). Vous pouvez détecter si URL.getRef () renvoie quelque chose qui pourrait être traité comme faisant partie du chemin d'accès et passer URL.getPath () + "#" + URL.getRef () comme paramètre "path" et null comme "fragment" "paramètre du constructeur de paramètres URI classe 7. Par défaut, la chaîne après # est traitée comme une référence (ou une ancre).
gouessej
49

une solution que j'ai développée et beaucoup plus stable que toute autre:

public class URLParamEncoder {

    public static String encode(String input) {
        StringBuilder resultStr = new StringBuilder();
        for (char ch : input.toCharArray()) {
            if (isUnsafe(ch)) {
                resultStr.append('%');
                resultStr.append(toHex(ch / 16));
                resultStr.append(toHex(ch % 16));
            } else {
                resultStr.append(ch);
            }
        }
        return resultStr.toString();
    }

    private static char toHex(int ch) {
        return (char) (ch < 10 ? '0' + ch : 'A' + ch - 10);
    }

    private static boolean isUnsafe(char ch) {
        if (ch > 128 || ch < 0)
            return true;
        return " %$&+,/:;=?@<>#%".indexOf(ch) >= 0;
    }

}
fmucar
la source
3
cela vous oblige également à casser l'url en morceaux. Il n'y a aucun moyen pour un ordinateur de savoir quelle partie de l'URL encoder. Voir ma modification ci-dessus
fmucar
4
@fmucar Merci pour ce morceau de code! Il convient de noter que ce n'est pas UTF-8. Pour obtenir UTF-8, il suffit de pré-traiter l'entrée avec String utf8Input = new String(Charset.forName("UTF-8").encode(input).array());(extrait d' ici )
letmaik
1
Cette solution encodera également la partie "http: //" en "http% 3A% 2F% 2F", ce que la question initiale a essayé d'éviter.
Benjamin Piette
2
Vous ne transmettez que ce dont vous avez besoin pour encoder, pas l'URL entière. Il n'y a aucun moyen de passer une chaîne d'URL entière et d'attendre un encodage correct. Dans tous les cas, vous devez diviser l'URL en ses éléments logiques.
fmucar
2
J'ai eu des problèmes avec cette réponse car elle n'encode pas les caractères non sécurisés en UTF-8. Cependant, elle peut dépendre de l'application homologue.
Tarnschaf
36

Si vous avez une URL, vous pouvez transmettre url.toString () à cette méthode. Décodez d'abord, pour éviter le double codage (par exemple, le codage d'un espace donne% 20 et le codage d'un signe de pourcentage donne% 25, ​​donc le double codage transformera un espace en% 2520). Ensuite, utilisez l'URI comme expliqué ci-dessus, en ajoutant toutes les parties de l'URL (afin de ne pas supprimer les paramètres de requête).

public URL convertToURLEscapingIllegalCharacters(String string){
    try {
        String decodedURL = URLDecoder.decode(string, "UTF-8");
        URL url = new URL(decodedURL);
        URI uri = new URI(url.getProtocol(), url.getUserInfo(), url.getHost(), url.getPort(), url.getPath(), url.getQuery(), url.getRef()); 
        return uri.toURL(); 
    } catch (Exception ex) {
        ex.printStackTrace();
        return null;
    }
}
Scott Izu
la source
1
URLDecoder.decode (chaîne, "UTF-8") échoue avec une exception IllegalArgumentException lorsque vous transmettez la chaîne en tant que " google.co.in/search?q=123%!123 ". Ceci est une URL valide. Je suppose que cette API ne fonctionne pas lorsque% est utilisé comme données au lieu du caractère de codage.
MediumOne
26

Ouais, l'encodage d'URL va encoder cette chaîne afin qu'elle soit passée correctement dans une URL vers une destination finale. Par exemple, vous ne pouvez pas avoir http://stackoverflow.com?url=http://yyy.com . UrlEncoding le paramètre fixerait cette valeur de paramètre.

J'ai donc deux choix pour vous:

  1. Avez-vous accès au chemin d'accès séparé du domaine? Si c'est le cas, vous pourrez peut-être simplement UrlEncode le chemin. Cependant, si ce n'est pas le cas, l'option 2 peut être pour vous.

  2. Obtenez commons-httpclient-3.1. Cela a une classe URIUtil:

    System.out.println (URIUtil.encodePath (" http://example.com/x y", "ISO-8859-1"));

Cela produira exactement ce que vous recherchez, car il ne codera que la partie chemin de l'URI.

Pour info, vous aurez besoin de commons-codec et commons-logging pour que cette méthode fonctionne lors de l'exécution.

Nathan Feger
la source
Sidenote apache commons a cessé apparemment de maintenir URIUtil dans les branches 4.x, vous recommandant plutôt d'utiliser la classe URI de JDK. Cela signifie simplement que vous devez rompre la chaîne vous-même.
Nicholi
2) Exactement, il est également suggéré ici stackoverflow.com/questions/5330104/… J'ai également utilisé la URIUtilsolution
Pour Kra
11

Nitpicking: une chaîne contenant un espace blanc par définition n'est pas un URI. Donc, ce que vous recherchez, c'est du code qui implémente l'échappement URI défini dans la section 2.1 de la RFC 3986 .

Julian Reschke
la source
Nous avons besoin du "comment" dans les réponses, pas du "quoi".
shinzou
11

Malheureusement, il org.apache.commons.httpclient.util.URIUtilest obsolète et le replacement org.apache.commons.codec.net.URLCodeccodage ne convient pas aux publications de formulaire, pas dans les URL réelles. J'ai donc dû écrire ma propre fonction, qui fait un seul composant (ne convient pas aux chaînes de requête entières qui ont des? Et des)

public static String encodeURLComponent(final String s)
{
  if (s == null)
  {
    return "";
  }

  final StringBuilder sb = new StringBuilder();

  try
  {
    for (int i = 0; i < s.length(); i++)
    {
      final char c = s.charAt(i);

      if (((c >= 'A') && (c <= 'Z')) || ((c >= 'a') && (c <= 'z')) ||
          ((c >= '0') && (c <= '9')) ||
          (c == '-') ||  (c == '.')  || (c == '_') || (c == '~'))
      {
        sb.append(c);
      }
      else
      {
        final byte[] bytes = ("" + c).getBytes("UTF-8");

        for (byte b : bytes)
        {
          sb.append('%');

          int upper = (((int) b) >> 4) & 0xf;
          sb.append(Integer.toHexString(upper).toUpperCase(Locale.US));

          int lower = ((int) b) & 0xf;
          sb.append(Integer.toHexString(lower).toUpperCase(Locale.US));
        }
      }
    }

    return sb.toString();
  }
  catch (UnsupportedEncodingException uee)
  {
    throw new RuntimeException("UTF-8 unsupported!?", uee);
  }
}
Jeff Tsay
la source
Allez, il doit y avoir une bibliothèque qui fait ça.
shinzou
9

URLEncoding peut très bien encoder les URL HTTP, comme vous l'avez malheureusement découvert. La chaîne que vous avez transmise, " http://search.barnesandnoble.com/booksearch/first book.pdf", était correctement et complètement codée dans un formulaire codé URL. Vous pouvez transmettre toute la longue chaîne de charabia que vous avez récupérée en tant que paramètre dans une URL, et elle peut être décodée exactement dans la chaîne que vous avez transmise.

Il semble que vous souhaitiez faire quelque chose d'un peu différent que de passer l'URL entière en tant que paramètre. D'après ce que je comprends, vous essayez de créer une URL de recherche qui ressemble à " http://search.barnesandnoble.com/booksearch/wwhatTheUserPassesIn ". La seule chose dont vous avez besoin pour encoder est le bit "anyTheUserPassesIn", donc peut-être que tout ce que vous avez à faire est quelque chose comme ceci:

String url = "http://search.barnesandnoble.com/booksearch/" + 
       URLEncoder.encode(userInput,"UTF-8");

Cela devrait produire quelque chose de plus valable pour vous.

Brandon Yarbrough
la source
17
Cela remplacerait les espaces dans userInput par "+". L'affiche doit être remplacée par "% 20".
vocaro
@vocaro: c'est un très bon point. URLEncoder s'échappe comme les arguments sont des paramètres de requête, pas comme le reste de l'URL.
Brandon Yarbrough
9

Si quelqu'un ne veut pas ajouter de dépendance à son projet, ces fonctions peuvent être utiles.

Nous passons ici la partie «chemin» de notre URL. Vous ne voulez probablement pas transmettre l'URL complète en tant que paramètre (les chaînes de requête nécessitent des échappements différents, etc.).

/**
 * Percent-encodes a string so it's suitable for use in a URL Path (not a query string / form encode, which uses + for spaces, etc)
 */
public static String percentEncode(String encodeMe) {
    if (encodeMe == null) {
        return "";
    }
    String encoded = encodeMe.replace("%", "%25");
    encoded = encoded.replace(" ", "%20");
    encoded = encoded.replace("!", "%21");
    encoded = encoded.replace("#", "%23");
    encoded = encoded.replace("$", "%24");
    encoded = encoded.replace("&", "%26");
    encoded = encoded.replace("'", "%27");
    encoded = encoded.replace("(", "%28");
    encoded = encoded.replace(")", "%29");
    encoded = encoded.replace("*", "%2A");
    encoded = encoded.replace("+", "%2B");
    encoded = encoded.replace(",", "%2C");
    encoded = encoded.replace("/", "%2F");
    encoded = encoded.replace(":", "%3A");
    encoded = encoded.replace(";", "%3B");
    encoded = encoded.replace("=", "%3D");
    encoded = encoded.replace("?", "%3F");
    encoded = encoded.replace("@", "%40");
    encoded = encoded.replace("[", "%5B");
    encoded = encoded.replace("]", "%5D");
    return encoded;
}

/**
 * Percent-decodes a string, such as used in a URL Path (not a query string / form encode, which uses + for spaces, etc)
 */
public static String percentDecode(String encodeMe) {
    if (encodeMe == null) {
        return "";
    }
    String decoded = encodeMe.replace("%21", "!");
    decoded = decoded.replace("%20", " ");
    decoded = decoded.replace("%23", "#");
    decoded = decoded.replace("%24", "$");
    decoded = decoded.replace("%26", "&");
    decoded = decoded.replace("%27", "'");
    decoded = decoded.replace("%28", "(");
    decoded = decoded.replace("%29", ")");
    decoded = decoded.replace("%2A", "*");
    decoded = decoded.replace("%2B", "+");
    decoded = decoded.replace("%2C", ",");
    decoded = decoded.replace("%2F", "/");
    decoded = decoded.replace("%3A", ":");
    decoded = decoded.replace("%3B", ";");
    decoded = decoded.replace("%3D", "=");
    decoded = decoded.replace("%3F", "?");
    decoded = decoded.replace("%40", "@");
    decoded = decoded.replace("%5B", "[");
    decoded = decoded.replace("%5D", "]");
    decoded = decoded.replace("%25", "%");
    return decoded;
}

Et des tests:

@Test
public void testPercentEncode_Decode() {
    assertEquals("", percentDecode(percentEncode(null)));
    assertEquals("", percentDecode(percentEncode("")));

    assertEquals("!", percentDecode(percentEncode("!")));
    assertEquals("#", percentDecode(percentEncode("#")));
    assertEquals("$", percentDecode(percentEncode("$")));
    assertEquals("@", percentDecode(percentEncode("@")));
    assertEquals("&", percentDecode(percentEncode("&")));
    assertEquals("'", percentDecode(percentEncode("'")));
    assertEquals("(", percentDecode(percentEncode("(")));
    assertEquals(")", percentDecode(percentEncode(")")));
    assertEquals("*", percentDecode(percentEncode("*")));
    assertEquals("+", percentDecode(percentEncode("+")));
    assertEquals(",", percentDecode(percentEncode(",")));
    assertEquals("/", percentDecode(percentEncode("/")));
    assertEquals(":", percentDecode(percentEncode(":")));
    assertEquals(";", percentDecode(percentEncode(";")));

    assertEquals("=", percentDecode(percentEncode("=")));
    assertEquals("?", percentDecode(percentEncode("?")));
    assertEquals("@", percentDecode(percentEncode("@")));
    assertEquals("[", percentDecode(percentEncode("[")));
    assertEquals("]", percentDecode(percentEncode("]")));
    assertEquals(" ", percentDecode(percentEncode(" ")));

    // Get a little complex
    assertEquals("[]]", percentDecode(percentEncode("[]]")));
    assertEquals("a=d%*", percentDecode(percentEncode("a=d%*")));
    assertEquals(")  (", percentDecode(percentEncode(")  (")));
    assertEquals("%21%20%2A%20%27%20%28%20%25%20%29%20%3B%20%3A%20%40%20%26%20%3D%20%2B%20%24%20%2C%20%2F%20%3F%20%23%20%5B%20%5D%20%25",
                    percentEncode("! * ' ( % ) ; : @ & = + $ , / ? # [ ] %"));
    assertEquals("! * ' ( % ) ; : @ & = + $ , / ? # [ ] %", percentDecode(
                    "%21%20%2A%20%27%20%28%20%25%20%29%20%3B%20%3A%20%40%20%26%20%3D%20%2B%20%24%20%2C%20%2F%20%3F%20%23%20%5B%20%5D%20%25"));

    assertEquals("%23456", percentDecode(percentEncode("%23456")));

}
Cuga
la source
Merci pour cela, mais que dois-je faire pour encoder un espace -> utiliser% 20 à la place selon votre exemple?
N00b Pr0grammer
Mis à jour pour tenir compte des espaces en tant que% 20
Cuga
7

Il y a toujours un problème si vous avez un "/" codé (% 2F) dans votre URL.

RFC 3986 - La section 2.2 dit: "Si les données d'un composant URI entraient en conflit avec l'objectif d'un caractère réservé en tant que délimiteur, alors les données en conflit doivent être codées en pourcentage avant que l'URI ne soit formé." (RFC 3986 - section 2.2)

Mais il y a un problème avec Tomcat:

http://tomcat.apache.org/security-6.html - Corrigé dans Apache Tomcat 6.0.10

important: traversée de répertoire CVE-2007-0450

Tomcat autorise '\', '% 2F' et '% 5C' [...].

Les propriétés du système Java suivantes ont été ajoutées à Tomcat pour fournir un contrôle supplémentaire de la gestion des délimiteurs de chemin dans les URL (les deux options par défaut sont false):

  • org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH: vrai | faux
  • org.apache.catalina.connector.CoyoteAdapter.ALLOW_BACKSLASH: true | false

En raison de l'impossibilité de garantir que toutes les URL sont traitées par Tomcat car elles se trouvent dans des serveurs proxy, Tomcat doit toujours être sécurisé comme si aucun proxy ne restreignant l'accès au contexte n'était utilisé.

Affecte: 6.0.0-6.0.9

Donc, si vous avez une URL avec le caractère% 2F, Tomcat retourne: "400 URI invalide: noSlash"

Vous pouvez désactiver le correctif dans le script de démarrage de Tomcat:

set JAVA_OPTS=%JAVA_OPTS% %LOGGING_CONFIG%   -Dorg.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH=true 
simonox
la source
7

J'ai lu les réponses précédentes pour écrire ma propre méthode car je ne pouvais pas faire fonctionner correctement quelque chose en utilisant la solution des réponses précédentes, cela me semble bien, mais si vous pouvez trouver une URL qui ne fonctionne pas avec cela, veuillez me le faire savoir.

public static URL convertToURLEscapingIllegalCharacters(String toEscape) throws MalformedURLException, URISyntaxException {
            URL url = new URL(toEscape);
            URI uri = new URI(url.getProtocol(), url.getUserInfo(), url.getHost(), url.getPort(), url.getPath(), url.getQuery(), url.getRef());
            //if a % is included in the toEscape string, it will be re-encoded to %25 and we don't want re-encoding, just encoding
            return new URL(uri.toString().replace("%25", "%"));
}
Emilien Brigand
la source
4

Je suis d'accord avec Matt. En effet, je ne l'ai jamais vu bien expliqué dans les didacticiels, mais une question est de savoir comment coder le chemin URL, et une toute autre est de savoir comment coder les paramètres qui sont ajoutés à l'URL (la partie requête, derrière le "? " symbole). Ils utilisent un encodage similaire, mais pas le même.

Spécialement pour l'encodage du caractère d'espace blanc. Le chemin URL doit être codé en% 20, tandis que la partie requête autorise% 20 et également le signe "+". La meilleure idée est de le tester par nous-mêmes sur notre serveur Web, à l'aide d'un navigateur Web.

Dans les deux cas, JE TOUJOURS coderais COMPOSANT PAR COMPOSANT , jamais la chaîne entière. En effet, URLEncoder le permet pour la partie requête. Pour la partie chemin, vous pouvez utiliser l'URI de classe, bien que dans ce cas, il demande la chaîne entière, pas un seul composant.

Quoi qu'il en soit, je crois que la meilleure façon d'éviter ces problèmes est d'utiliser une conception personnelle non conflictuelle. Comment? Par exemple, je ne nommerais jamais de répertoires ou de paramètres utilisant d'autres caractères que aZ, AZ, 0-9 et _. De cette façon, le seul besoin est de coder la valeur de chaque paramètre, car il peut provenir d'une entrée utilisateur et les caractères utilisés sont inconnus.

negora
la source
2
un exemple de code utilisant l'URL dans la question serait une bonne chose à mettre dans votre réponse
Martin Serrano
3

Peut-être pouvez-vous essayer UriUtils dans org.springframework.web.util

UriUtils.encodeUri(input, "UTF-8")
micahli123
la source
3

Vous pouvez également utiliser GUAVAet utiliser Escaper: UrlEscapers.urlFragmentEscaper().escape(relativePath)

À Kra
la source
2

En plus de la réponse de Carlos Heuberger: si un autre que le défaut (80) est nécessaire, le constructeur 7 param doit être utilisé:

URI uri = new URI(
        "http",
        null, // this is for userInfo
        "www.google.com",
        8080, // port number as int
        "/ig/api",
        "weather=São Paulo",
        null);
String request = uri.toASCIIString();
Martin Dimitrov
la source
2

J'ai pris le contenu ci-dessus et l'ai changé un peu. J'aime d'abord la logique positive et je pensais qu'un HashSet pourrait donner de meilleures performances que certaines autres options, comme la recherche dans une chaîne. Bien que je ne sois pas sûr que la pénalité d'autoboxing en vaille la peine, mais si le compilateur optimise pour les caractères ASCII, le coût de la boxe sera faible.

/***
 * Replaces any character not specifically unreserved to an equivalent 
 * percent sequence.
 * @param s
 * @return
 */
public static String encodeURIcomponent(String s)
{
    StringBuilder o = new StringBuilder();
    for (char ch : s.toCharArray()) {
        if (isSafe(ch)) {
            o.append(ch);
        }
        else {
            o.append('%');
            o.append(toHex(ch / 16));
            o.append(toHex(ch % 16));
        }
    }
    return o.toString();
}

private static char toHex(int ch)
{
    return (char)(ch < 10 ? '0' + ch : 'A' + ch - 10);
}

// https://tools.ietf.org/html/rfc3986#section-2.3
public static final HashSet<Character> UnreservedChars = new HashSet<Character>(Arrays.asList(
        'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
        'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z',
        '0','1','2','3','4','5','6','7','8','9',
        '-','_','.','~'));
public static boolean isSafe(char ch)
{
    return UnreservedChars.contains(ch);
}
ChrisG65
la source
1

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

0. Testez si l'URL est déjà encodée .

1. Split URL en parties structurelles. Utilisez java.net.URL pour cela.

2. Codez correctement chaque pièce structurelle!

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

4. Utilisez java.net.URI.toASCIIString()pour coder en pourcentage, unicode codé NFC - (mieux serait NFKC!).

Trouvez plus ici: https://stackoverflow.com/a/49796882/1485527

jschnasse
la source
0

J'ai créé un nouveau projet pour aider à construire des URL HTTP. La bibliothèque encodera automatiquement les segments de chemin et les paramètres de requête par URL.

Vous pouvez afficher la source et télécharger un binaire sur https://github.com/Widen/urlbuilder

L'URL d'exemple dans cette question:

new UrlBuilder("search.barnesandnoble.com", "booksearch/first book.pdf").toString()

produit

http://search.barnesandnoble.com/booksearch/first%20book.pdf

Uriah Carpenter
la source
0

J'ai eu le même problème. Résolu ce problème en supprimant:

android.net.Uri.encode(urlString, ":/");

Il code la chaîne mais ignore ":" et "/".

Richard R
la source
0

j'utilise ceci

org.apache.commons.text.StringEscapeUtils.escapeHtml4("my text % & < >");

ajouter cette dépendance

 <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-text</artifactId>
        <version>1.8</version>
    </dependency>
développeur learn999
la source
-2

Je développe une bibliothèque à cet effet: les galimatias . Il analyse l'URL de la même manière que les navigateurs Web. Autrement dit, si une URL fonctionne dans un navigateur, elle sera correctement analysée par les galimatias .

Dans ce cas:

// Parse
io.mola.galimatias.URL.parse(
    "http://search.barnesandnoble.com/booksearch/first book.pdf"
).toString()

Vous donnera: http://search.barnesandnoble.com/booksearch/first%20book.pdf. Bien sûr, c'est le cas le plus simple, mais cela fonctionnera avec n'importe quoi, bien au-delà java.net.URI.

Vous pouvez le vérifier sur: https://github.com/smola/galimatias

smola
la source
-3

Vous pouvez utiliser une fonction comme celle-ci. Complétez et modifiez-le selon vos besoins:

/**
     * Encode URL (except :, /, ?, &, =, ... characters)
     * @param url to encode
     * @param encodingCharset url encoding charset
     * @return encoded URL
     * @throws UnsupportedEncodingException
     */
    public static String encodeUrl (String url, String encodingCharset) throws UnsupportedEncodingException{
            return new URLCodec().encode(url, encodingCharset).replace("%3A", ":").replace("%2F", "/").replace("%3F", "?").replace("%3D", "=").replace("%26", "&");
    }

Exemple d'utilisation:

String urlToEncode = ""http://www.growup.com/folder/intérieur-à_vendre?o=4";
Utils.encodeUrl (urlToEncode , "UTF-8")

Le résultat est: http://www.growup.com/folder/int%C3%A9rieur-%C3%A0_vendre?o=4

Salim Hamidi
la source
1
Cette réponse est incomplète sans URLCodec.
Marquis de Lorne
upvote pour le chaînage .replace (), ce n'est pas l'idéal mais c'est suffisant pour les cas d'utilisation ad-hoc de base
svarog
-5

String url = "" http://search.barnesandnoble.com/booksearch/ ;

Ce sera constant, je suppose, et seul le nom de fichier change de manière dynamique, alors obtenez le nom de fichier

String filename; // récupère le nom du fichier

String urlEnc = url + fileName.replace ("", "% 20");

raja
la source
2
Et tous les autres personnages illégaux?
Marquis de Lorne
-7

Que diriez-vous:

public String UrlEncode (String in_) {

String retVal = "";

try {
    retVal = URLEncoder.encode(in_, "UTF8");
} catch (UnsupportedEncodingException ex) {
    Log.get().exception(Log.Level.Error, "urlEncode ", ex);
}

return retVal;

}

MichaelICE
la source
URLEncoder ne peut pas être utilisé pour échapper des caractères d'URL ivalides. Uniquement pour encoder des formulaires.
Archer