Jak dekodować adresy URL w Javie?


323

W Javie chcę przekonwertować to:

https%3A%2F%2Fmywebsite%2Fdocs%2Fenglish%2Fsite%2Fmybook.do%3Frequest_type

Do tego:

https://mywebsite/docs/english/site/mybook.do&request_type

Oto co mam do tej pory:

class StringUTF 
{
    public static void main(String[] args) 
    {
        try{
            String url = 
               "https%3A%2F%2Fmywebsite%2Fdocs%2Fenglish%2Fsite%2Fmybook.do" +
               "%3Frequest_type%3D%26type%3Dprivate";

            System.out.println(url+"Hello World!------->" +
                new String(url.getBytes("UTF-8"),"ASCII"));
        }
        catch(Exception E){
        }
    }
}

Ale to nie działa dobrze. Jak nazywają się te %3Ai %2Fformaty i jak je przekonwertować?


@Stephen .. Dlaczego adres URL nie może być kodowany w UTF-8 String ..?
crackerplace

Problem polega na tym, że ponieważ adres URL może mieć postać UTF-8, pytanie naprawdę nie ma nic wspólnego z UTF-8. Odpowiednio zredagowałem pytanie.
Chris Jester-Young

Może to być (teoretycznie), ale ciąg w twoim przykładzie nie jest łańcuchem zakodowanym w UTF-8. Jest to ciąg ASCII zakodowany w adresie URL. Stąd tytuł wprowadza w błąd.
Stephen C

Warto również zauważyć, że wszystkie znaki w urlciągu są ASCII, i jest to prawdą również po zdekodowaniu ciągu. '%'jest znakiem ASCII i %xxreprezentuje znak ASCII, jeśli xxjest mniejszy niż (szesnastkowy) 80.
Stephen C

Odpowiedzi:


634

Nie ma to nic wspólnego z kodowaniem znaków, takich jak UTF-8 lub ASCII. Ciąg, który tam masz, jest zakodowany w adresie URL . Ten rodzaj kodowania jest czymś zupełnie innym niż kodowanie znaków.

Wypróbuj coś takiego:

try {
    String result = java.net.URLDecoder.decode(url, StandardCharsets.UTF_8.name());
} catch (UnsupportedEncodingException e) {
    // not going to happen - value came from JDK's own StandardCharsets
}

Java 10 dodała bezpośrednie wsparcie dla CharsetAPI, co oznacza, że ​​nie ma potrzeby wychwytywania wyjątku UnsupportedEncodingException:

String result = java.net.URLDecoder.decode(url, StandardCharsets.UTF_8);

Zauważ, że kodowanie znaków (takie jak UTF-8 lub ASCII) decyduje o odwzorowaniu znaków na surowe bajty. Dobre wprowadzenie do kodowania znaków znajduje się w tym artykule .


1
Włączone metody URLDecodersą statyczne, więc nie musisz tworzyć nowej instancji.
laz

2
@Trismegistos Tylko wersja, w której nie określono kodowania znaków (drugi parametr, "UTF-8") jest nieaktualna zgodnie z dokumentacją interfejsu API języka Java 7. Użyj wersji z dwoma parametrami.
Jesper,

23
Jeśli przy użyciu języka Java 1.7+ można używać wersji statycznej z „UTF-8” ciąg: StandardCharsets.UTF_8.name()z tego pakietu: java.nio.charset.StandardCharsets. Odpowiedni do tego: link
Shahar

1
W przypadku kodowania znaków jest to świetny artykuł zbyt balusc.blogspot.in/2009/05/unicode-how-to-get-characters-right.html
crackerplace

4
Uważaj na to. Jak wspomniano tutaj: blog.lunatech.com/2009/02/03/… Nie chodzi tu o adresy URL, ale o kodowanie formularzy HTML.
Michał


47

To zostało odebrane przed (choć ta kwestia była pierwsza!):

„Aby to zrobić, należy użyć java.net.URI, ponieważ klasa URLDecoder dokonuje dekodowania w formacie x-www-urlencoded, co jest nieprawidłowe (pomimo nazwy, dotyczy danych formularza).”

Jak stwierdza dokumentacja klasy URL :

Zalecanym sposobem zarządzania kodowaniem i dekodowaniem adresów URL jest użycie identyfikatora URI i konwersja między tymi dwiema klasami za pomocą toURI () i URI.toURL () .

W URLEncoder i URLDecoder klasy mogą być również stosowane, ale tylko dla kodowanie HTML formularza, który nie jest taki sam jak schemat kodowania zdefiniowane w RFC2396 .

Gruntownie:

String url = "https%3A%2F%2Fmywebsite%2Fdocs%2Fenglish%2Fsite%2Fmybook.do%3Frequest_type";
System.out.println(new java.net.URI(url).getPath());

da tobie:

https://mywebsite/docs/english/site/mybook.do?request_type

6
W Javie 1.7 URLDecoder.decode(String, String)przeciążenie nie jest przestarzałe. Musisz odnosić się do URLDecoder.decode(String)przeciążenia bez kodowania. Możesz zaktualizować swój post dla wyjaśnienia.
Aaron

2
Ta odpowiedź jest myląca; ten cytat blokowy nie ma nic wspólnego ze zwolnieniem. Javadoc metody przestarzałej stwierdza, a ja cytuję@deprecated The resulting string may vary depending on the platform's default encoding. Instead, use the decode(String,String) method to specify the encoding.
Emerson Farrugia

1
Funkcja getPath () dla identyfikatorów URI zwraca tylko część ścieżki identyfikatora URI, jak wspomniano powyżej.
Pelpotronic,

2
O ile się nie mylę, wiadomo, że „ścieżka” jest częścią URI po części autorytatywnej (patrz: en.wikipedia.org/wiki/Uniform_Resource_Identifier dla definicji ścieżki) - wydaje mi się, że widzę zachowanie to standardowe / prawidłowe zachowanie. Używam java 1.8.0_101 (na Android Studio). Byłbym ciekawy, co otrzymasz, gdy wywoływana jest funkcja „getAuthority ()”. Nawet ten artykuł / przykład wydaje się wskazywać, że ścieżka jest tylko / public / manual / devices
Pelpotronic

1
@Pelpotronic Kod w poście faktycznie wyświetla wydruk, który pokazuje (przynajmniej dla mnie). Myślę, że powodem tego jest to, że z powodu kodowania adresu URL konstruktor URI faktycznie traktuje cały ciąg ( https%3A%2F...) jako tylko ścieżkę URI; nie ma uprawnień ani zapytań itp. Można to przetestować, wywołując odpowiednie metody get na obiekcie URI. Jeśli przekażesz zdekodowany tekst do konstruktora URI:, new URI("https://mywebsite/do.....")wówczas wywołanie getPath()i inne metody dadzą poprawne wyniki.
Kröw

14

%3Ai %2Fsą znakami zakodowanymi w adresie URL. Użyj tego kodu Java, aby przekonwertować je z powrotem na :i/

String decoded = java.net.URLDecoder.decode(url, "UTF-8");

2
nie konwertuje też% 2C, jest (,)
vuhung3990

to musi być zapakowane w blok try / catch. czytaj więcej o sprawdzonych wyjątkach (tym) kontra niesprawdzony stackoverflow.com/questions/6115896/...
Bruno Wolff

5
 try {
        String result = URLDecoder.decode(urlString, "UTF-8");
    } catch (UnsupportedEncodingException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

5
public String decodeString(String URL)
    {

    String urlString="";
    try {
        urlString = URLDecoder.decode(URL,"UTF-8");
        } catch (UnsupportedEncodingException e) {
            // TODO Auto-generated catch block

        }

        return urlString;

    }

4
Czy mógłby Pan uściślić swoją odpowiedź, dodając nieco więcej opisu oferowanego rozwiązania?
abarisone


2
import java.io.UnsupportedEncodingException;
import java.net.URISyntaxException;

public class URLDecoding { 

    String decoded = "";

    public String decodeMethod(String url) throws UnsupportedEncodingException
    {
        decoded = java.net.URLDecoder.decode(url, "UTF-8"); 
        return  decoded;
//"You should use java.net.URI to do this, as the URLDecoder class does x-www-form-urlencoded decoding which is wrong (despite the name, it's for form data)."
    }

    public String getPathMethod(String url) throws URISyntaxException 
    {
        decoded = new java.net.URI(url).getPath();  
        return  decoded; 
    }

    public static void main(String[] args) throws UnsupportedEncodingException, URISyntaxException 
    {
        System.out.println(" Here is your Decoded url with decode method : "+ new URLDecoding().decodeMethod("https%3A%2F%2Fmywebsite%2Fdocs%2Fenglish%2Fsite%2Fmybook.do%3Frequest_type")); 
        System.out.println("Here is your Decoded url with getPath method : "+ new URLDecoding().getPathMethod("https%3A%2F%2Fmywebsite%2Fdocs%2Fenglish%2Fsite%2Fmybook.do%3Frequest")); 

    } 

}

Możesz mądrze wybrać metodę :)


0

Za pomocą klasy java.net.URI:

public String getDecodedURL(String encodedUrl) {
    try {
        URI uri = new URI(encodedUrl);
        return uri.getScheme() + ":" + uri.getSchemeSpecificPart();
    } catch (Exception e) {
        return "";
    }
}

Pamiętaj, że obsługa wyjątków może być lepsza, ale nie ma to większego znaczenia w tym przykładzie.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.