Kodowanie parametrów zapytania URL w Javie

109

Jak zakodować parametry zapytania, aby przejść do adresu URL w Javie? Wiem, to wydaje się oczywiste i już zadane pytanie.

Są dwie subtelności, których nie jestem pewien:

  1. Czy spacje powinny być zakodowane w adresie URL jako „+” czy „% 20”? W chrome, jeśli wpiszę „http://google.com/foo=?bar me”, chrome zmieni go na kodowanie z% 20
  2. Czy konieczne / poprawne jest kodowanie dwukropków „:” jako% 3B? Chrome tego nie robi.

Uwagi:

  • java.net.URLEncoder.encodewygląda na to, że nie działa, wydaje się, że kodowanie danych ma być przesłane do formularza. Na przykład koduje spację jako +zamiast %20i koduje dwukropek, który nie jest konieczny.
  • java.net.URI nie koduje parametrów zapytania
Alex Black
źródło
To pytanie wygląda na przydatne: stackoverflow.com/questions/444112/…
Alex Black
2
struktura części zapytania jest zależna od serwera, chociaż większość oczekuje application/x-www-form-urlencodedpar klucz / wartość. Zobacz tutaj, aby uzyskać więcej: nielegalneargumentexception.blogspot.com/2009/12/…
McDowell

Odpowiedzi:

128

java.net.URLEncoder.encode(String s, String encoding)też może pomóc. Jest zgodny z kodowaniem formularza HTML application/x-www-form-urlencoded.

URLEncoder.encode(query, "UTF-8");

Z drugiej strony kodowanie procentowe (znane również jako kodowanie adresów URL ) koduje spację za pomocą %20. Dwukropek jest znakiem zastrzeżonym, więc :po zakodowaniu pozostanie dwukropkiem.

Buhake Sindi
źródło
3
Wspomniałem, że nie sądzę, że to robi kodowanie url, zamiast tego koduje dane, które mają być przesłane za pośrednictwem formularza. komentarze?
Alex Black,
Dzieje się tak, ponieważ URLEncoderjest zgodny z application/x-www-form-urlencodedformatem MIME (który jest prawidłowym kodowaniem formularza HTML). Zakładam, że nie tego szukasz.
Buhake Sindi
6
Skończyło się na tym, że użyłem URLEncoder.encode i zamieniłem „+” na „% 20”
Alex Black
2
Koduje ukośniki do „% 2F”, czy nie powinien pozostawić ukośników URL bez zmian?
golimar
6
@golimar Nie, nie powinno. Powinieneś podać tylko wartość parametru, a nie cały adres URL. Rozważ przykład http://example.com/?url=http://example.com/?q=c&sort=name. Powinien kodować &sort=nameczy nie? Nie ma sposobu, aby odróżnić wartość od adresu URL. To jest dokładny powód, dla którego potrzebujesz kodowania wartości w pierwszej kolejności.
Pijusn
15

EDYCJA: URIUtilnie jest już dostępna w nowszych wersjach, lepsza odpowiedź w Java - zakoduj URL lub przez pana Sindi w tym wątku.


URIUtilof Apache httpclient jest naprawdę przydatne, chociaż istnieje kilka alternatyw

URIUtil.encodeQuery(url);

Na przykład koduje spację jako „+” zamiast „% 20”

Oba są doskonale uzasadnione we właściwym kontekście . Chociaż jeśli naprawdę wolisz, możesz wydać zastąpienie ciągu.

Johan Sjöberg
źródło
Musiałbym się zgodzić. Użyj HttpClient, będziesz o wiele szczęśliwszy.
DaShaun
Wygląda obiecująco, przypadkowo dostałeś link? Szukam w Google, ale znajduję wiele.
Alex Black,
1
Ta metoda nie wydaje się być obecna w HttpClient 4.1? hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/org/…
Alex Black
@Alex, hmm to irytujące, zawsze stosowałem tę procedurę z dobrymi wynikami. Jednym z pomysłów jest pobranie kodu źródłowego z wydania 3, ponieważ teraz najwyraźniej nie chcieli go już dłużej utrzymywać.
Johan Sjöberg,
1
URIUtil.encodeWithinQueryjest tym, czego użyłbyś do zakodowania indywidualnego parametru zapytania, o co wydawało się pytać oryginalne pytanie.
Jesse Glick
13

Niestety, URLEncoder.encode () nie generuje prawidłowego kodowania procentowego (jak określono w RFC 3986 ).

URLEncoder.encode () koduje wszystko dobrze, z wyjątkiem spacji zakodowanej na „+”. Wszystkie kodery Java URI, które udało mi się znaleźć, ujawniają tylko publiczne metody kodowania zapytania, fragmentu, części ścieżki itp. - ale nie ujawniają "surowego" kodowania. Jest to niefortunne, ponieważ fragmenty i zapytanie mogą zakodować spację do +, więc nie chcemy ich używać. Ścieżka jest poprawnie zakodowana, ale najpierw jest „znormalizowana”, więc nie możemy jej również użyć do kodowania „ogólnego”.

Najlepsze rozwiązanie, jakie mogłem wymyślić:

return URLEncoder.encode(raw, "UTF-8").replaceAll("\\+", "%20");

Jeśli replaceAll()jest dla ciebie za wolny, myślę, że alternatywą jest zrolowanie własnego kodera ...

EDYCJA: Najpierw miałem ten kod, który nie koduje poprawnie znaków „?”, „&”, „=”:

//don't use - doesn't properly encode "?", "&", "="
new URI(null, null, null, raw, null).toString().substring(1);
Kosta
źródło
+jest całkowicie poprawnym kodowaniem spacji.
Lawrence Dol
@LawrenceDol to prawda, ale czasami +może być interpretowane nieprawidłowo - spójrz na C # blogs.msdn.microsoft.com/yangxind/2006/11/08/...
Lu55
To. Porównałem różne alternatywy z encodeURIComponentwynikami metody Javascript i było to jedyne dokładne dopasowanie do tych, które wypróbowałem (zapytania ze spacjami, tureckimi i niemieckimi znakami specjalnymi).
Utku Özdemir
8

Nie jest konieczne kodowanie dwukropka jako% 3B w zapytaniu, chociaż nie jest to nielegalne.

URI         = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
query       = *( pchar / "/" / "?" )
pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
pct-encoded   = "%" HEXDIG HEXDIG
sub-delims    = "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / ";" / "="

Wydaje się również, że tylko spacje zakodowane w procentach są prawidłowe, ponieważ wątpię, czy spacja jest ALFA lub CYFRA

więcej szczegółów znajdziesz w specyfikacji URI .

Edwin Buck
źródło
Może to jednak zmienić znaczenie identyfikatora URI, ponieważ interpretacja ciągu zapytania należy do serwera. Jeśli tworzysz application/x-www-form-urlencodedciąg zapytania, jedno i drugie jest w porządku. Jeśli naprawiasz adres URL, który użytkownik wpisał / wkleił, :powinien pozostać w spokoju.
tc.
@tc. Masz rację, jeśli dwukropek jest używany jako ogólny separator (strona 12 dokumentu RFC); jeśli jednak nie jest używany jako ogranicznik ogólny, oba kodowania powinny być rozwiązywane identycznie.
Edwin Buck
Musisz także uważać, ponieważ adresy URL nie są tak naprawdę podzbiorem URI: adamgent.com/post/25161273526/urls-are-not-a-subset-of-uris
Adam Gent
5

Wbudowany Java URLEncoder robi to, co powinien i powinieneś go używać.

A „+” lub „% 20” są zarówno ważne zamienniki znak spacji w adresie URL. Każdy z nich zadziała.

Znak „:” powinien być zakodowany, ponieważ jest to znak separatora. tj. http: // foo lub ftp: // bar . Fakt, że dana przeglądarka może to obsłużyć, gdy nie jest zakodowany, nie oznacza, że ​​jest poprawny. Powinieneś je zakodować.

Dobrą praktyką jest używanie metody, która przyjmuje parametr kodowania znaków. UTF-8 jest tam generalnie używany, ale powinieneś podać go wyraźnie.

URLEncoder.encode(yourUrl, "UTF-8");
rfeak
źródło
5
+jest tylko reprezentacją przestrzeni w application/x-www-form-urlencoded; nie ma gwarancji, że będzie działać, nawet jeśli jest ograniczone do protokołu HTTP. Podobnie :jest poprawny w ciągu zapytania i nie powinien być konwertowany na %3B; serwer może je interpretować inaczej.
tc.
1
ta metoda kodowania również całych ukośniki URL i inne znaki, które są częścią np http://do http%3A%2F%2Fktórych nie jest poprawna
Aby Kra
2
@ ToKra nie powinieneś kodować http://części. Metoda dotyczy parametrów zapytania i zakodowanych danych formularza. Jeśli jednak chciałbyś przekazać adres URL innej witryny jako parametr zapytania, WTEDY chciałbyś go zakodować, aby uniknąć pomylenia parsera URL.
beldaz
@tc Mój odczyt z w3.org/TR/html4/interact/forms.html#h-17.13.3.3 jest taki, że wszystkie dane formularzy GET są kodowane jako application/x-www-form-urlencodedtyp zawartości. Czy to nie znaczy, że musi działać dla HTTP?
beldaz
0

jeśli masz tylko problem ze spacją w adresie URL. Użyłem poniższego kodu i działa dobrze

String url;
URL myUrl = new URL(url.replace(" ","%20"));

przykład: adres URL to

www.xyz.com?para=hello sir

to wyjście muUrl to

www.xyz.com?para=hello%20sir

Jignesh Patel
źródło
0
String param="2019-07-18 19:29:37";
param="%27"+param.trim().replace(" ", "%20")+"%27";

Zauważyłem, że w przypadku Datetime (Timestamp) URLEncoder.encode(param,"UTF-8")nie działa.

Sprzedaż ICL EXIMON
źródło