391 Stimmen

HTTP-URL-Adresskodierung in Java

Meine Java-Standalone-Anwendung erhält vom Benutzer eine URL (die auf eine Datei verweist), und ich muss sie anklicken und herunterladen. Das Problem, das ich konfrontiert bin, ist, dass ich nicht in der Lage bin, die HTTP-URL-Adresse richtig zu kodieren...

Ejemplo:

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

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

gibt mich zurück:

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

Aber was ich will, ist

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

(Leerzeichen ersetzt durch %20)

Ich denke URLEncoder ist nicht dafür ausgelegt, HTTP-URLs zu kodieren... In der JavaDoc heißt es "Utility class for HTML form encoding"... Gibt es eine andere Möglichkeit, dies zu tun?

27voto

Nathan Feger Punkte 18486

Ja, die URL-Kodierung wird diese Zeichenfolge so kodieren, dass sie ordnungsgemäß in einer URL an ein endgültiges Ziel weitergegeben wird. Zum Beispiel könnte man nicht haben http://stackoverflow.com?url=http://yyy.com . UrlEncoding der Parameter würde diesen Parameterwert fixieren.

Ich habe also zwei Möglichkeiten für Sie:

  1. Haben Sie Zugriff auf den Pfad unabhängig von der Domäne? Wenn ja, können Sie den Pfad möglicherweise einfach mit UrlEncode verschlüsseln. Wenn dies jedoch nicht der Fall ist, kann Option 2 für Sie geeignet sein.

  2. Holen Sie sich commons-httpclient-3.1. Dies hat eine Klasse URIUtil:

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

Dies gibt genau das aus, wonach Sie suchen, da es nur den Pfadteil des URI kodiert.

FYI, benötigen Sie commons-codec und commons-logging für diese Methode zur Laufzeit zu arbeiten.

14voto

Cuga Punkte 17251

Wenn jemand keine Abhängigkeit zu seinem Projekt hinzufügen möchte, können diese Funktionen hilfreich sein.

Wir übergeben hier den "Pfad"-Teil unserer URL. Wahrscheinlich möchten Sie nicht die gesamte URL als Parameter übergeben (Abfragezeichenfolgen benötigen verschiedene Escapes usw.).

/**
 * 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;
}

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

}

11voto

Jeff Tsay Punkte 136

Leider, org.apache.commons.httpclient.util.URIUtil ist veraltet, und die replacement org.apache.commons.codec.net.URLCodec eignet sich für die Kodierung von Formularen, nicht für die eigentlichen URLs. Also musste ich meine eigene Funktion schreiben, die eine einzelne Komponente ausführt (nicht geeignet für ganze Abfrage-Strings, die ? und &s enthalten)

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

10voto

Brandon Yarbrough Punkte 34849

URLEncoding kann HTTP-URLs sehr gut kodieren, wie Sie leider feststellen mussten. Die von Ihnen übergebene Zeichenkette, " http://search.barnesandnoble.com/booksearch/first book.pdf", wurde korrekt und vollständig in eine URL-kodierte Form gebracht. Sie könnten die gesamte lange Zeichenfolge des Kauderwelschs, die Sie zurückbekommen haben, als Parameter in einer URL übergeben, und sie könnte wieder in genau die Zeichenfolge dekodiert werden, die Sie eingegeben haben.

Es klingt, als wollten Sie etwas anderes tun, als die gesamte URL als Parameter zu übergeben. Soweit ich weiß, versuchen Sie, eine Such-URL zu erstellen, die aussieht wie " http://search.barnesandnoble.com/booksearch/whateverTheUserPassesIn ". Das Einzige, was Sie kodieren müssen, ist das "whateverTheUserPassesIn"-Bit, so dass Sie vielleicht nur etwas wie dies tun müssen:

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

Das sollte für Sie etwas mehr Aussagekraft haben.

8voto

Emilien Brigand Punkte 8323

Ich habe die vorherigen Antworten gelesen, um meine eigene Methode zu schreiben, weil ich mit der Lösung der vorherigen Antworten nicht richtig arbeiten konnte. Für mich sieht es gut aus, aber wenn Sie eine URL finden, die nicht mit dieser funktioniert, lassen Sie es mich bitte wissen.

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

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X