Anleitung zur Java-URL-Codierung/-Decodierung

Anleitung zur Java-URL-Codierung / -Decodierung

1. Einführung

Einfach ausgedrückt übersetztURL encoding Sonderzeichen von der URL in eine Darstellung, die der Spezifikation entspricht und korrekt verstanden und interpretiert werden kann.

In diesem Artikel konzentrieren wir uns aufhow to encode/decode the URL or form data, damit es der Spezifikation entspricht und korrekt über das Netzwerk übertragen wird.

2. Analysieren Sie die URL

Die grundlegende Syntax vonURIkann wie folgt verallgemeinert werden:

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

Der erste Schritt beim Codieren eines URI besteht darin, seine Teile zu untersuchen und dann nur die relevanten Teile zu codieren.

Schauen wir uns ein Beispiel für einen URI an:

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

Eine Möglichkeit zur Analyse des URI besteht darin, die String-Darstellung in die Klassejava.net.URIzu laden:

@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"));
}

Die KlasseURI analysiert die URL der Zeichenfolgendarstellung und macht ihre Teile über eine einfache API verfügbar - z. B.getXXX.

3. Codieren Sie die URL

Bei der Kodierung von URIs besteht eine der häufigsten Gefahren darin, den gesamten URI zu kodieren. Normalerweise müssen wir nur den Abfrageteil der URI codieren.

Codieren wir die Daten mit der Methodeencode(data, encodingScheme)der KlasseURLEncoder:

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

Die Methodeencodeakzeptiert zwei Parameter:

  1. data - zu übersetzender String

  2. encodingScheme - Name der Zeichenkodierung

Dieseencode-Methode konvertiert die Zeichenfolge in dasapplication/x-www-form-urlencoded-Format.

Das Codierungsschema konvertiert Sonderzeichen in eine zweistellige hexadezimale Darstellung von 8 Bits, die in Form von „%xy“ dargestellt werden. Wenn wir es mit Pfadparametern zu tun haben oder dynamische Parameter hinzufügen, werden wir die Daten verschlüsseln und dann an den Server senden.

Note: Die Empfehlung vonWorld Wide Web Consortium besagt, dassUTF-8 verwendet werden sollte. Andernfalls kann es zu Inkompatibilitäten kommen. (Referenz:https://docs.oracle.com/javase/7/docs/api/java/net/URLEncoder.html)

4. Dekodieren Sie die URL

Lassen Sie uns nun die vorherige URL mit der Dekodierungsmethode vonURLDecoder dekodieren:

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

Die zwei wichtigen Punkte hier sind:

  • Analysieren Sie die URL vor dem Dekodieren

  • Verwenden Sie dasselbe Kodierungsschema für die Kodierung und Dekodierung

Wenn wir dekodieren als analysieren, werden URL-Teile möglicherweise nicht richtig analysiert. Wenn wir ein anderes Codierungsschema verwenden, um die Daten zu decodieren, führt dies zu Datenmüll.

5. Codieren Sie ein Pfadsegment

URLEncoder kann nicht zum Codieren des Pfadsegments derURL verwendet werden. Die Pfadkomponente bezieht sich auf die hierarchische Struktur, die einen Verzeichnispfad darstellt, oder dient zum Auffinden von Ressourcen, die durch“/” getrennt sind.

Reservierte Zeichen im Pfadsegment unterscheiden sich von den Abfrageparameterwerten. Beispielsweise ist ein "+" - Zeichen ein gültiges Zeichen im Pfadsegment und sollte daher nicht codiert werden.

Um das Pfadsegment zu codieren, verwenden wir stattdessen die KlasseUriUtilsvon Spring Framework. Die KlasseUriUtils bietet die MethodenencodePath undencodePathSegment zum Codieren des Pfads bzw. des Pfadsegments.

Schauen wir uns ein Beispiel an:

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

Im obigen Codeausschnitt können wir sehen, dass bei Verwendung der MethodeencodePathSegmentder codierte Wert zurückgegeben wurde und + nicht codiert wird, da es sich um ein Wertzeichen in der Pfadkomponente handelt.

Fügen wir unserer Test-URL eine Pfadvariable hinzu:

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

und um eine richtig codierte URL zusammenzustellen und zu bestätigen, ändern wir den Test von Abschnitt 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. Fazit

In diesem Tutorial haben wir gesehen, wie die Daten codiert und decodiert werden, damit sie korrekt übertragen und interpretiert werden können. Während sich der Artikel auf das Codieren / Decodieren von URI-Abfrageparameterwerten konzentrierte, gilt der Ansatz auch für HTML-Formularparameter.

Sie finden den Quellcodeover on GitHub.