Codifica dell'indirizzo URL HTTP in Java


366

La mia applicazione autonoma Java ottiene un URL (che punta a un file) dall'utente e devo selezionarlo e scaricarlo. Il problema che sto affrontando è che non sono in grado di codificare correttamente l'indirizzo URL HTTP ...

Esempio:

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

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

mi restituisce:

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

Ma quello che voglio è

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

(spazio sostituito da% 20)

Immagino che URLEncodernon sia progettato per codificare URL HTTP ... JavaDoc dice "Classe di utilità per la codifica dei moduli HTML" ... Esiste un altro modo per farlo?



Il comportamento è del tutto corretto. La codifica URL consiste nel trasformare qualcosa in una stringa che può essere tranquillamente passata come parametro URL e non interpretata affatto come URL. Considerando che vuoi solo convertire una piccola parte dell'URL.
Stephen Holt,

Risposte:


303

La classe java.net.URI può aiutare; nella documentazione dell'URL che trovi

Nota, la classe URI esegue l'escaping dei suoi campi componenti in determinate circostanze. Il modo consigliato per gestire la codifica e la decodifica degli URL è utilizzare un URI

Usa uno dei costruttori con più di un argomento, come:

URI uri = new URI(
    "http", 
    "search.barnesandnoble.com", 
    "/booksearch/first book.pdf",
    null);
URL url = uri.toURL();
//or String request = uri.toString();

(il costruttore a argomento singolo dell'URI NON sfugge ai caratteri illegali)


Solo i caratteri illegali vengono salvati dal codice sopra - NON sfugge ai caratteri non ASCII (vedi il commento di Fatih).
Il toASCIIStringmetodo può essere utilizzato per ottenere una stringa solo con caratteri US-ASCII:

URI uri = new URI(
    "http", 
    "search.barnesandnoble.com", 
    "/booksearch/é",
    null);
String request = uri.toASCIIString();

Per un URL con una query simile http://www.google.com/ig/api?weather=São Paulo, utilizzare la versione a 5 parametri del costruttore:

URI uri = new URI(
        "http", 
        "www.google.com", 
        "/ig/api",
        "weather=São Paulo",
        null);
String request = uri.toASCIIString();

13
Nota: la classe URI menzionata qui proviene da "org.apache.commons.httpclient.URI" non "java.net", l'URI "java.net" non accetta i caratteri illegali, a meno che tu non utilizzi costruttori che costruiscono URL dai suoi componenti, come il modo menzionato nel commento di Matt in basso
Mohamed Faramawi,

7
@Mohamed: la classe che ho citato e usato per i test in realtà è java.net.URI : ha funzionato perfettamente (Java 1.6). Vorrei menzionare il nome completo della classe se non fosse quello standard Java e il collegamento rimanda alla documentazione di java.net.URI. E, con il commento di Sudhakar, ha risolto il problema senza includere "librerie comuni"!
user85421

1
URI uri = nuovo URI ("http", "search.barnesandnoble.com", "/ booksearch / é", null); L'escaping corretto non con questo campione? Questo avrebbe dovuto essere evitato con%
escape

@fatih - esatto, grazie! Normalmente questo non dovrebbe essere un problema, ma esiste una soluzione semplice, quasi uguale a quella che ho scritto prima. Vedi 2a modifica.
user85421

@Carlos Thx per la modifica. Ora scappa ma non corregge correttamente. Dovrebbe aggiungere un% al valore esadecimale di char per i parametri Path che significa che char deve essere convertito in% e9
fmucar

91

Si prega di essere avvisati che la maggior parte delle risposte di cui sopra sono ERRATE.

La URLEncoderclasse, nonostante il nome, NON è ciò che deve essere qui. È un peccato che Sun abbia nominato questa classe in modo così fastidioso. URLEncoderè pensato per passare i dati come parametri, non per codificare l'URL stesso.

In altre parole, "http://search.barnesandnoble.com/booksearch/first book.pdf"è l'URL. I parametri sarebbero, ad esempio "http://search.barnesandnoble.com/booksearch/first book.pdf?parameter1=this&param2=that",. I parametri sono ciò per cui useresti URLEncoder.

I seguenti due esempi evidenziano le differenze tra i due.

Quanto segue produce parametri errati, secondo lo standard HTTP. Nota la e commerciale (&) e più (+) sono codificati in modo errato.

uri = new URI("http", null, "www.google.com", 80, 
"/help/me/book name+me/", "MY CRZY QUERY! +&+ :)", null);

// URI: http://www.google.com:80/help/me/book%20name+me/?MY%20CRZY%20QUERY!%20+&+%20:)

Quanto segue produrrà i parametri corretti, con la query codificata correttamente. Nota gli spazi, le e commerciali e i segni più.

uri = new URI("http", null, "www.google.com", 80, "/help/me/book name+me/", URLEncoder.encode("MY CRZY QUERY! +&+ :)", "UTF-8"), null);

// URI: http://www.google.com:80/help/me/book%20name+me/?MY+CRZY+QUERY%2521+%252B%2526%252B+%253A%2529

2
Esatto, il costruttore dell'URI codifica già la stringa di query , secondo la documentazione docs.oracle.com/javase/1.4.2/docs/api/java/net/… , java.lang.String, java.lang.String, int , java.lang.String, java.lang.String, java.lang.String)
madoke,

8
@Draemon La risposta è corretta ma utilizza la stringa di query in un modo non comune; un esempio più normale potrebbe essere query = URLEncoder.encode(key) + "=" + URLEncoder.encode(value). I documenti dicono semplicemente che "viene citato qualsiasi carattere che non sia un carattere URI legale".
tc.

1
Sono d'accordo con Matt qui. Se digiti questo URL: " google.com/help/me/book name + me /? MY CRZY QUERY! + & + :)" in un browser, codifica automaticamente gli spazi ma "&" viene utilizzato come valore della query separatore e "+" vanno persi.
arcot

80

Ho intenzione di aggiungere un suggerimento qui rivolto agli utenti Android. Puoi farlo, evitando così di avere librerie esterne. Inoltre, tutte le soluzioni di ricerca / sostituzione di caratteri suggerite in alcune delle risposte precedenti sono pericolose e dovrebbero essere evitate.

Prova questo:

String urlStr = "http://abc.dev.domain.com/0007AC/ads/800x480 15sec h.264.mp4";
URL url = new URL(urlStr);
URI uri = new URI(url.getProtocol(), url.getUserInfo(), url.getHost(), url.getPort(), url.getPath(), url.getQuery(), url.getRef());
url = uri.toURL();

Puoi vedere che in questo particolare URL, devo avere quegli spazi codificati in modo da poterlo usare per una richiesta.

Questo sfrutta un paio di funzionalità disponibili per te nelle lezioni Android. Innanzitutto, la classe URL può suddividere un URL nei relativi componenti, quindi non è necessario eseguire alcuna ricerca / sostituzione di stringhe. In secondo luogo, questo approccio sfrutta la funzionalità della classe URI di componenti con escape corretto quando si costruisce un URI tramite componenti anziché da una singola stringa.

La bellezza di questo approccio è che puoi prendere qualsiasi stringa di URL valida e farla funzionare senza bisogno di alcuna conoscenza speciale di te stesso.


3
Ottimo approccio, ma vorrei sottolineare che questo codice non impedisce la doppia codifica , ad esempio% 20 è stato codificato in% 2520. La risposta di Scott non ne soffre.
Nattster

2
Non può gestire #.
Alston,

O se vuoi solo fare la quotazione del percorso: nuovo URI (null, null, "/ percorso con spazi", null, null) .toString ()
user1050755

1
@Stallman Se il nome del tuo file contiene #, la classe URL lo inserirà in "ref" (equivalente di "frammento" nella classe URI). È possibile rilevare se URL.getRef () restituisce qualcosa che potrebbe essere trattato come parte del percorso e passare URL.getPath () + "#" + URL.getRef () come parametro "percorso" e null come "frammento" "parametro del costruttore di parametri di classe 7 URI. Per impostazione predefinita, la stringa dopo # viene trattata come riferimento (o ancora).
Gouessej,

49

una soluzione che ho sviluppato e molto più stabile di qualsiasi altra:

public class URLParamEncoder {

    public static String encode(String input) {
        StringBuilder resultStr = new StringBuilder();
        for (char ch : input.toCharArray()) {
            if (isUnsafe(ch)) {
                resultStr.append('%');
                resultStr.append(toHex(ch / 16));
                resultStr.append(toHex(ch % 16));
            } else {
                resultStr.append(ch);
            }
        }
        return resultStr.toString();
    }

    private static char toHex(int ch) {
        return (char) (ch < 10 ? '0' + ch : 'A' + ch - 10);
    }

    private static boolean isUnsafe(char ch) {
        if (ch > 128 || ch < 0)
            return true;
        return " %$&+,/:;=?@<>#%".indexOf(ch) >= 0;
    }

}

3
ciò richiede anche che tu rompa l'URL in pezzi. Non c'è modo per un computer di sapere quale parte dell'URL codificare. Vedi la mia modifica sopra
fmucar

4
@fmucar Grazie per quel pezzo di codice! Va notato che questo non è UTF-8. Per ottenere UTF-8 basta pre-elaborare l'input con String utf8Input = new String(Charset.forName("UTF-8").encode(input).array());(preso da qui )
letmaik

1
Questa soluzione in realtà codificherà anche la parte "http: //" in "http% 3A% 2F% 2F", che è ciò che la domanda iniziale ha cercato di evitare.
Benjamin Piette,

2
Passi solo ciò che devi codificare, non l'intero URL. Non c'è modo di passare un'intera stringa URL e aspettarsi una codifica corretta. In tutti i casi, è necessario suddividere l'URL nelle sue parti logiche.
fmucar,

2
Ho avuto problemi con questa risposta perché non codifica caratteri non sicuri in UTF-8 .. potrebbe dipendere dall'applicazione peer.
Tarnschaf,

36

Se hai un URL, puoi passare url.toString () in questo metodo. Prima decodifica, per evitare la doppia codifica (ad esempio, la codifica di uno spazio comporta% 20 e la codifica di un segno di percentuale comporta% 25, ​​quindi la doppia codifica trasformerà uno spazio in% 2520). Quindi, utilizza l'URI come spiegato sopra, aggiungendo tutte le parti dell'URL (in modo da non eliminare i parametri della query).

public URL convertToURLEscapingIllegalCharacters(String string){
    try {
        String decodedURL = URLDecoder.decode(string, "UTF-8");
        URL url = new URL(decodedURL);
        URI uri = new URI(url.getProtocol(), url.getUserInfo(), url.getHost(), url.getPort(), url.getPath(), url.getQuery(), url.getRef()); 
        return uri.toURL(); 
    } catch (Exception ex) {
        ex.printStackTrace();
        return null;
    }
}

1
URLDecoder.decode (stringa, "UTF-8") non riesce con un'eccezione IllegalArgumentException quando si passa la stringa come " google.co.in/search?q=123%!123 ". Questo è un URL valido. Immagino che questa API non funzioni quando% viene utilizzato come dati anziché come carattere di codifica.
MediumOne,

26

Sì, la codifica URL sta per codificare quella stringa in modo che venga passata correttamente in un URL a una destinazione finale. Ad esempio, non è possibile avere http://stackoverflow.com?url=http://yyy.com . La codifica Url del parametro avrebbe corretto quel valore di parametro.

Quindi ho due scelte per te:

  1. Hai accesso al percorso separato dal dominio? In tal caso, potresti semplicemente essere in grado di UrlEncode il percorso. Tuttavia, in caso contrario, l'opzione 2 potrebbe essere adatta a te.

  2. Ottieni commons-httpclient-3.1. Questo ha una classe URIUtil:

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

Questo produrrà esattamente ciò che stai cercando, poiché codificherà solo la parte del percorso dell'URI.

Cordiali saluti, avrai bisogno di codec commons e registrazione comune per questo metodo per funzionare in fase di esecuzione.


I beni comuni di Sidenote Apache hanno smesso di mantenere URIUtil apparentemente nei rami 4.x, raccomandando invece di usare la classe URI di JDK. Significa solo che devi spezzare la corda da solo.
Nicholi,

2) Esattamente è anche suggerito qui stackoverflow.com/questions/5330104/… Ho anche usato la URIUtilsoluzione
Per Kra

11

Nitpicking: una stringa contenente un carattere di spazio bianco per definizione non è un URI. Quindi quello che stai cercando è il codice che implementa l'escaping dell'URI definito nella Sezione 2.1 della RFC 3986 .


Abbiamo bisogno del "come" nelle risposte, non del "cosa".
shinzou,

11

Sfortunatamente, org.apache.commons.httpclient.util.URIUtilè deprecato e la replacement org.apache.commons.codec.net.URLCodeccodifica adatta per i post dei moduli, non negli URL effettivi. Quindi ho dovuto scrivere la mia funzione, che fa un singolo componente (non adatto a intere stringhe di query che hanno? 'S & & s)

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

Dai, ci deve essere una biblioteca che fa questo.
shinzou,

9

URLEncoding può codificare bene gli URL HTTP, come sfortunatamente hai scoperto. La stringa che hai passato, " http://search.barnesandnoble.com/booksearch/first book.pdf", è stata correttamente e completamente codificata in un modulo con codifica URL. Potresti passare l'intera lunga stringa di gobbledigook che hai restituito come parametro in un URL e potrebbe essere decodificato nuovamente nella stringa che hai passato.

Sembra che tu voglia fare qualcosa di leggermente diverso dal passare l'intero URL come parametro. Da quello che raccolgo, stai cercando di creare un URL di ricerca che assomigli a " http://search.barnesandnoble.com/booksearch/whateverTheUserPassesIn ". L'unica cosa che devi codificare è il bit "whateverTheUserPassesIn", quindi forse tutto ciò che devi fare è qualcosa del genere:

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

Ciò dovrebbe produrre qualcosa di più valido per te.


17
Ciò sostituirà gli spazi in userInput con "+". Il poster deve essere sostituito con "% 20".
vocaro,

@vocaro: questo è un ottimo punto. URLEncoder scappa come gli argomenti sono parametri di query, non come il resto dell'URL.
Brandon Yarbrough,

9

Se qualcuno non vuole aggiungere una dipendenza al proprio progetto, queste funzioni potrebbero essere utili.

Passiamo la parte "percorso" del nostro URL qui. Probabilmente non vuoi passare l'URL completo come parametro (le stringhe di query richiedono escape diversi, ecc.).

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

E test:

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

}

Grazie per questo, ma cosa devo fare per codificare uno spazio -> usa% 20 invece come nel tuo esempio?
N00b Pr0grammer

Aggiornato per tenere conto degli spazi come% 20
Cuga

7

C'è ancora un problema se hai un "/" codificato (% 2F) nel tuo URL.

RFC 3986 - La Sezione 2.2 dice: "Se i dati per un componente URI sarebbero in conflitto con lo scopo di un carattere riservato come delimitatore, i dati in conflitto devono essere codificati in percentuale prima che si formi l'URI." (RFC 3986 - Sezione 2.2)

Ma c'è un problema con Tomcat:

http://tomcat.apache.org/security-6.html - Risolto in Apache Tomcat 6.0.10

importante: Directory traversal CVE-2007-0450

Tomcat consente '\', '% 2F' e '% 5C' [...].

Le seguenti proprietà del sistema Java sono state aggiunte a Tomcat per fornire un ulteriore controllo sulla gestione dei delimitatori di percorso negli URL (entrambe le opzioni sono impostate su false):

  • org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH: true | false
  • org.apache.catalina.connector.CoyoteAdapter.ALLOW_BACKSLASH: true | false

A causa dell'impossibilità di garantire che tutti gli URL siano gestiti da Tomcat come nei server proxy, Tomcat dovrebbe essere sempre protetto come se non fosse utilizzato alcun proxy che limitasse l'accesso al contesto.

Colpisce: 6.0.0-6.0.9

Quindi, se hai un URL con il carattere% 2F, Tomcat restituisce: "400 URI non valido: noSlash"

È possibile cambiare la correzione bug nello script di avvio Tomcat:

set JAVA_OPTS=%JAVA_OPTS% %LOGGING_CONFIG%   -Dorg.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH=true 

7

Ho letto le risposte precedenti per scrivere il mio metodo perché non potevo avere qualcosa che funzionasse correttamente usando la soluzione delle risposte precedenti, mi sembra buono ma se riesci a trovare un URL che non funziona con questo, per favore fatemelo sapere.

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

4

Sono d'accordo con Matt. In effetti, non l'ho mai visto ben spiegato nei tutorial, ma una questione è come codificare il percorso dell'URL, e uno molto diverso è come codificare i parametri che sono aggiunti all'URL (la parte della query, dietro il "? "simbolo). Usano una codifica simile, ma non la stessa.

Specialmente per la codifica del carattere dello spazio bianco. Il percorso URL deve essere codificato come% 20, mentre la parte della query consente% 20 e anche il segno "+". L'idea migliore è testarla da soli sul nostro server Web, utilizzando un browser Web.

In entrambi i casi, I SEMPRE codificherei SEMPRE COMPONENTE PER COMPONENTE , mai l'intera stringa. Infatti URLEncoder lo consente per la parte di query. Per la parte percorso è possibile utilizzare l'URI di classe, sebbene in questo caso richieda l'intera stringa, non un singolo componente.

Ad ogni modo, credo che il modo migliore per evitare questi problemi sia usare un design personale non conflittuale. Come? Ad esempio, non nominerei mai directory o parametri usando caratteri diversi da aZ, AZ, 0-9 e _. In questo modo, l'unica necessità è codificare il valore di ogni parametro, poiché potrebbe provenire da un input dell'utente e i caratteri utilizzati sono sconosciuti.


2
codice di esempio che utilizza l'URL nella domanda sarebbe una buona cosa per inserire la tua risposta
Martin Serrano


3

Puoi anche usare GUAVAe tracciare escaper: UrlEscapers.urlFragmentEscaper().escape(relativePath)


2

Oltre alla risposta di Carlos Heuberger: se è necessario un valore diverso da quello predefinito (80), è necessario utilizzare il costruttore a 7 parametri:

URI uri = new URI(
        "http",
        null, // this is for userInfo
        "www.google.com",
        8080, // port number as int
        "/ig/api",
        "weather=São Paulo",
        null);
String request = uri.toASCIIString();

2

Ho preso il contenuto sopra e l'ho cambiato un po '. Mi piace prima la logica positiva e ho pensato che un HashSet potesse fornire prestazioni migliori rispetto ad alcune altre opzioni, come la ricerca attraverso una stringa. Tuttavia, non sono sicuro se la pena di boxe automatica valga la pena, ma se il compilatore ottimizza per i caratteri ASCII, il costo della boxe sarà basso.

/***
 * Replaces any character not specifically unreserved to an equivalent 
 * percent sequence.
 * @param s
 * @return
 */
public static String encodeURIcomponent(String s)
{
    StringBuilder o = new StringBuilder();
    for (char ch : s.toCharArray()) {
        if (isSafe(ch)) {
            o.append(ch);
        }
        else {
            o.append('%');
            o.append(toHex(ch / 16));
            o.append(toHex(ch % 16));
        }
    }
    return o.toString();
}

private static char toHex(int ch)
{
    return (char)(ch < 10 ? '0' + ch : 'A' + ch - 10);
}

// https://tools.ietf.org/html/rfc3986#section-2.3
public static final HashSet<Character> UnreservedChars = new HashSet<Character>(Arrays.asList(
        'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
        'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z',
        '0','1','2','3','4','5','6','7','8','9',
        '-','_','.','~'));
public static boolean isSafe(char ch)
{
    return UnreservedChars.contains(ch);
}

1

Utilizzare la seguente soluzione Java standard (supera circa 100 casi di test forniti da Web Plattform Test ):

0. Verifica se l'URL è già codificato .

1. Suddividere l'URL in parti strutturali. Usalo java.net.URL per questo.

2. Codificare correttamente ogni parte strutturale!

3. Utilizzare IDN.toASCII(putDomainNameHere)per Punycode codificare il nome host!

4. Usare java.net.URI.toASCIIString()per codificare in percentuale, Unicode con codifica NFC - (meglio sarebbe NFKC!).

Scopri di più qui: https://stackoverflow.com/a/49796882/1485527


0

Ho creato un nuovo progetto per aiutare a costruire URL HTTP. La libreria codificherà automaticamente l'URL per segmenti di percorso e parametri di query.

Puoi visualizzare la fonte e scaricare un file binario su https://github.com/Widen/urlbuilder

L'URL di esempio in questa domanda:

new UrlBuilder("search.barnesandnoble.com", "booksearch/first book.pdf").toString()

produce

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


0

Ho avuto lo stesso problema. Risolto questo da unsing:

android.net.Uri.encode(urlString, ":/");

Codifica la stringa ma salta ":" e "/".


0

lo uso

org.apache.commons.text.StringEscapeUtils.escapeHtml4("my text % & < >");

aggiungi questa dipendenza

 <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-text</artifactId>
        <version>1.8</version>
    </dependency>

-2

Sviluppo una biblioteca che serve a questo scopo: le galimatie . Analizza l'URL nello stesso modo dei browser web. Cioè, se un URL funziona in un browser, verrà analizzato correttamente dalle galimatie .

In questo caso:

// Parse
io.mola.galimatias.URL.parse(
    "http://search.barnesandnoble.com/booksearch/first book.pdf"
).toString()

Vi darà: http://search.barnesandnoble.com/booksearch/first%20book.pdf. Naturalmente questo è il caso più semplice, ma funzionerà con qualsiasi cosa, molto oltre java.net.URI.

Puoi verificarlo su: https://github.com/smola/galimatias


-3

Puoi usare una funzione come questa. Completalo e modificalo secondo le tue necessità:

/**
     * Encode URL (except :, /, ?, &, =, ... characters)
     * @param url to encode
     * @param encodingCharset url encoding charset
     * @return encoded URL
     * @throws UnsupportedEncodingException
     */
    public static String encodeUrl (String url, String encodingCharset) throws UnsupportedEncodingException{
            return new URLCodec().encode(url, encodingCharset).replace("%3A", ":").replace("%2F", "/").replace("%3F", "?").replace("%3D", "=").replace("%26", "&");
    }

Esempio di utilizzo:

String urlToEncode = ""http://www.growup.com/folder/intérieur-à_vendre?o=4";
Utils.encodeUrl (urlToEncode , "UTF-8")

Il risultato è: http://www.growup.com/folder/int%C3%A9rieur-%C3%A0_vendre?o=4


1
Questa risposta è incompleta senza URLCodec.
Marchese di Lorne,

valuto per il concatenamento .replace (), non è l'ideale ma è sufficiente per i casi d'uso di base ad hoc
svarog


-7

Che ne dite di:

public String UrlEncode (String in_) {

String retVal = "";

try {
    retVal = URLEncoder.encode(in_, "UTF8");
} catch (UnsupportedEncodingException ex) {
    Log.get().exception(Log.Level.Error, "urlEncode ", ex);
}

return retVal;

}


URLEncoder non può essere utilizzato per sfuggire ai caratteri URL ivalidi. Solo per codificare i moduli.
Arciere
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.