Guide pour l’encodage/décodage d’URL Java

Guide de codage / décodage d'URL Java

1. introduction

En termes simples,URL encoding traduit les caractères spéciaux de l'URL en une représentation conforme aux spécifications et pouvant être correctement comprise et interprétée.

Dans cet article, nous allons nous concentrer surhow to encode/decode the URL or form data afin qu'il respecte les spécifications et transmette correctement sur le réseau.

2. Analysez l'URL

Une syntaxe de base deURI peut être généralisée comme:

scheme:[//[user:[email protected]]host[:port]][/]path[?query][#fragment]

La première étape du codage d’un URI consiste à examiner ses parties et à ne coder que les parties pertinentes.

Regardons un exemple d'URI:

String testUrl =
  "http://www.example.com?key1=value+1&key2=value%40%21%242&key3=value%253";

Une façon d'analyser l'URI consiste à charger la représentation String dans une classejava.net.URI:

@Test
public void givenURL_whenAnalyze_thenCorrect() throws Exception {
    URI uri = new URI(testUrl);

    assertThat(uri.getScheme(), is("http"));
    assertThat(uri.getHost(), is("www.example.com"));
    assertThat(uri.getRawQuery(),
      .is("key1=value+1&key2=value%40%21%242&key3=value%253"));
}

La classeURI analyse l'URL de représentation sous forme de chaîne et expose ses parties via une API simple - par exemple,getXXX.

3. Encoder l'URL

Lors du codage de l'URI, l'un des pièges courants est le codage de l'URI complet. En règle générale, nous ne devons encoder que la partie requête de l'URI.

Encodons les données en utilisant la méthodeencode(data, encodingScheme) de la classeURLEncoder:

private String encodeValue(String value) {
    return URLEncoder.encode(value, StandardCharsets.UTF_8.toString());
}

@Test
public void givenRequestParam_whenUTF8Scheme_thenEncode() throws Exception {
    Map requestParams = new HashMap<>();
    requestParams.put("key1", "value 1");
    requestParams.put("key2", "[email protected]!$2");
    requestParams.put("key3", "value%3");

    String encodedURL = requestParams.keySet().stream()
      .map(key -> key + "=" + encodeValue(requestParams.get(key)))
      .collect(joining("&", "http://www.example.com?", ""));

    assertThat(testUrl, is(encodedURL));

La méthodeencode accepte deux paramètres:

  1. data - chaîne à traduire

  2. encodingScheme - nom du codage de caractères

Cette méthodeencode convertit la chaîne au formatapplication/x-www-form-urlencoded.

Le schéma d'encodage convertira les caractères spéciaux en deux chiffres de représentation hexadécimale de 8 bits qui seront représentés sous la forme de «%xy». Lorsque nous traitons de paramètres de chemin ou que nous ajoutons des paramètres dynamiques, nous encodons les données puis les envoyons au serveur.

Note: La recommandationWorld Wide Web Consortium stipule queUTF-8 doit être utilisé. Ne pas le faire peut introduire des incompatibilités. (Référence:https://docs.oracle.com/javase/7/docs/api/java/net/URLEncoder.html)

4. Décoder l'URL

Décodons maintenant l'URL précédente en utilisant la méthode de décodage desURLDecoder:

private String decode(String value) {
    return URLDecoder.decode(value, StandardCharsets.UTF_8.toString());
}

@Test
public void givenRequestParam_whenUTF8Scheme_thenDecodeRequestParams() {
    URI uri = new URI(testUrl);

    String scheme = uri.getScheme();
    String host = uri.getHost();
    String query = uri.getRawQuery();

    String decodedQuery = Arrays.stream(query.split("&"))
      .map(param -> param.split("=")[0] + "=" + decode(param.split("=")[1]))
      .collect(Collectors.joining("&"));

    assertEquals(
      "http://www.example.com?key1=value 1&[email protected]!$2&key3=value%3",
      scheme + "://" + host + "?" + decodedQuery);
}

Les deux bits importants ici sont:

  • analyser l'URL avant le décodage

  • utiliser le même schéma de codage pour le codage et le décodage

Si nous décodions plutôt qu'analyser, les portions d'URL pourraient ne pas être analysées correctement. Si nous utilisions un autre schéma de codage pour décoder les données, cela produirait des données parasites.

5. Encoder un segment de chemin

URLEncoder ne peut pas être utilisé pour coder le segment de chemin desURL. Le composant Path fait référence à la structure hiérarchique qui représente un chemin de répertoire, ou il sert à localiser les ressources séparées par“/”.

Les caractères réservés dans le segment de chemin sont différents des valeurs de paramètres de requête. Par exemple, un signe "+" est un caractère valide dans le segment de chemin et ne doit donc pas être codé.

Pour encoder le segment de chemin, nous utilisons à la place la classeUriUtils de Spring Framework. La classeUriUtils fournit les méthodesencodePath etencodePathSegment pour coder respectivement le chemin et le segment de chemin.

Prenons un exemple:

private String encodePath(String path) {
    try {
        path = UriUtils.encodePath(path, "UTF-8");
    } catch (UnsupportedEncodingException e) {
        LOGGER.error("Error encoding parameter {}", e.getMessage(), e);
    }
    return path;
}
@Test
public void givenPathSegment_thenEncodeDecode()
  throws UnsupportedEncodingException {
    String pathSegment = "/Path 1/Path+2";
    String encodedPathSegment = encodePath(pathSegment);
    String decodedPathSegment = UriUtils.decode(encodedPathSegment, "UTF-8");

    assertEquals("/Path%201/Path+2", encodedPathSegment);
    assertEquals("/Path 1/Path+2", decodedPathSegment);
}

Dans l'extrait de code ci-dessus, nous pouvons voir que lorsque nous avons utilisé la méthodeencodePathSegment, elle a renvoyé la valeur encodée et + n'est pas encodé car il s'agit d'un caractère de valeur dans le composant de chemin.

Ajoutons une variable de chemin à notre URL de test:

String testUrl
  = "/path+1?key1=value+1&key2=value%40%21%242&key3=value%253";

et pour assembler et affirmer une URL correctement codée, changeons le test de la section 2:

String path = "path+1";
String encodedURL = requestParams.keySet().stream()
  .map(k -> k + "=" + encodeValue(requestParams.get(k)))
  .collect(joining("&", "/" + encodePath(path) + "?", ""));
assertThat(testUrl, CoreMatchers.is(encodedURL));

6. Conclusion

Dans ce didacticiel, nous avons vu comment encoder et décoder les données afin qu’elles puissent être transférées et interprétées correctement. Bien que l'article se concentre sur le codage / décodage des valeurs de paramètre de requête URI, l'approche s'applique également aux paramètres de formulaire HTML.

Vous pouvez trouver le code sourceover on GitHub.