Java'da HTTP URL Adresi Kodlaması


366

Java bağımsız uygulamam kullanıcıdan bir URL (bir dosyaya işaret eder) alır ve onu vurup indirmem gerekiyor. Karşılaştığım sorun HTTP URL adresini düzgün bir şekilde kodlayamıyorum ...

Misal:

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

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

beni döndürür:

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

Ama istediğim

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

(boşluk% 20 ile değiştirildi)

Bence URLEncoderHTTP URL'lerini kodlamak için tasarlanmamıştır ... JavaDoc "HTML form kodlaması için faydalı sınıf" diyor ... Bunu yapmanın başka bir yolu var mı?



Davranış tamamen doğrudur. URL kodlaması, bir şeyi URL parametresi olarak güvenli bir şekilde geçirilebilen ve hiç URL olarak yorumlanmayan bir dizeye dönüştürmektir. Halbuki URL'nin sadece küçük bir bölümünü dönüştürmesini istiyorsunuz.
Stephen Holt

Yanıtlar:


303

Java.net.URI sınıfı yardımcı olabilir; bulduğunuz URL'nin belgelerinde

URI sınıfı, belirli durumlarda bileşen alanlarından kaçmayı gerçekleştirir. URL'lerin kodlanmasını ve kodunun çözülmesini yönetmenin önerilen yolu bir URI kullanmaktır

Birden fazla argümana sahip kuruculardan birini kullanın, örneğin:

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

(URI'nin tek değişkenli kurucusu geçersiz karakterlerden kaçmaz)


Sadece yasadışı karakterler yukarıdaki koddan kaçar - ASCII olmayan karakterlerden kaçmaz (bkz. Fatih'in yorumu). Yöntem yalnızca US-ASCII karakterlerle bir dize almak için kullanılabilir:
toASCIIString

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

Sorgusu olan bir URL için, kurucunun http://www.google.com/ig/api?weather=São Paulo5 parametreli sürümünü kullanın:

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

13
Burada belirtilen URI sınıfının, "java.net" değil "org.apache.commons.httpclient.URI" sınıfından geldiğini, "java.net", siz kullanmadıkça URI geçersiz karakterleri kabul etmiyor aşağıdaki Matt yorumunda belirtildiği gibi bileşenlerinden URL oluşturan
inşaatçılar

7
@Mohamed: Test etmek için bahsettiğim ve kullandığım sınıf aslında java.net.URI : mükemmel çalıştı (Java 1.6). Standart Java bir değilse tam nitelikli sınıf adını ve bağlantı belgelerine işaret ediyorum java.net.URI. Ve Sudhakar'ın yorumuyla, sorunu "ortak kütüphaneler" içermeden çözdü!
user85421

1
URI uri = yeni URI ("http", "search.barnesandnoble.com", "/ booksearch / é", null); Bu örnekle kaçmayı doğru yapmıyor mu? Bu,% escapes ile
kaçmalıydı

@fatih - bu doğru, teşekkürler! Normalde bu bir sorun olmamalı, ancak basit bir çözüm var - neredeyse daha önce yazdığımla aynı. Bkz. 2. düzenleme.
user85421

@Carlos Düzenleme için Thx. Şimdi kaçıyor ama kaçmayı düzeltmiyor. Bu é kömürü anlam Yol parametreleri için kömürün HEX değerine% ekleyerek olmalıdır% e9 dönüştürülmesi gerekir
fmucar

91

Lütfen yukarıdaki cevapların çoğunun YANLIŞ olduğuna dikkat edin.

URLEncoderSınıf, isim rağmen burada ne olması gerektiğine DEĞİLDİR. Sun'ın bu sınıfı çok sinir bozucu bir şekilde adlandırması talihsiz bir durum. URLEncoderURL'nin kendisini kodlamak için değil, parametreleri parametre olarak iletmek içindir.

Başka bir deyişle, "http://search.barnesandnoble.com/booksearch/first book.pdf"URL. Parametreler, örneğin olacaktır "http://search.barnesandnoble.com/booksearch/first book.pdf?parameter1=this&param2=that". Parametreler sizin için ne kullanılır URLEncoder.

Aşağıdaki iki örnek, ikisi arasındaki farkları vurgulamaktadır.

Aşağıdaki, HTTP standardına göre yanlış parametreler üretir. Ve işaretinin (&) ve artı (+) yanlış kodlandığını unutmayın.

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

Aşağıdaki sorgu doğru kodlanmış doğru parametreleri üretecektir. Boşlukları, ve işaretlerini ve artı işaretlerini not edin.

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
Doğru, URI yapıcısı docs.oracle.com/javase/1.4.2/docs/api/java/net/… , java.lang.String, java.lang.String, int belgelerine göre sorgu dizesini zaten kodluyor , java.lang.String, java.lang.String, java.lang.String)
madoke

8
@Draemon Yanıt doğrudur, ancak sorgu dizesini nadiren kullanır; daha normal bir örnek olabilir query = URLEncoder.encode(key) + "=" + URLEncoder.encode(value). Dokümanlar yalnızca "yasal bir URI karakteri olmayan herhangi bir karakterin alıntılandığını" söylüyorlar.
tc.

1
Burada Matt ile aynı fikirdeyim. Bu URL'yi yazarsanız: " google.com/help/me/book name + me /? CRZY QUERY! + & + :)" bir tarayıcıda otomatik olarak boşlukları kodlar, ancak "&" sorgu değeri olarak kullanılır ayırıcı ve "+" kaybolur.
arcot

80

Burada Android kullanıcılarına yönelik bir öneri ekleyeceğim. Bunu herhangi bir harici kütüphane almak zorunda kalmadan yapabilirsiniz. Ayrıca, yukarıdaki cevapların bazılarında önerilen tüm arama / değiştirme karakterleri çözümleri tehlikelidir ve bundan kaçınılmalıdır.

Bunu deneyin:

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

Bu özel URL'de, bir istek için kullanabilmem için bu boşlukların kodlanmış olması gerektiğini görebilirsiniz.

Bu, Android sınıflarında kullanabileceğiniz birkaç özellikten yararlanır. İlk olarak, URL sınıfı bir URL'yi uygun bileşenlerine ayırabilir, böylece herhangi bir dize arama / değiştirme işi yapmanız gerekmez. İkincisi, bu yaklaşım, tek bir dizeden ziyade bileşenler aracılığıyla bir URI oluşturduğunuzda, bileşenlerden düzgün kaçan URI sınıfı özelliğinden yararlanır.

Bu yaklaşımın güzelliği, herhangi bir geçerli URL dizesini alıp, kendiniz hakkında herhangi bir özel bilgiye ihtiyaç duymadan çalışmasını sağlamanızdır.


3
Güzel bir yaklaşım, ama bu kod çift ​​kodlama , örneğin% 20% 2520 kodlanmış var engellemiyor işaret etmek istiyorum . Scott'ın cevabı bundan muzdarip değildir.
nattster

2
Üstesinden gelemez #.
Alston

Veya yalnızca yol alıntısı yapmak istiyorsanız: yeni URI (null, null, "/ boşluklu yol", null, null) .toString ()
user1050755

1
@Stallman Dosya adınız # içeriyorsa, URL sınıfı bunu "ref" (URI sınıfındaki "fragment" e eşdeğer) içine koyacaktır. URL.getRef () yönteminin yolun bir parçası olarak değerlendirilebilecek bir şey döndürüp döndürmediğini algılayabilir ve URL.getPath () + "#" + URL.getRef () öğesinin "path" parametresi olarak ve "fragman" olarak null değerini iletebilirsiniz. msgstr "URI sınıfı 7 parametre yapıcısının parametresi." Varsayılan olarak, # işaretinden sonraki dize başvuru (veya bağlantı) olarak kabul edilir.
gouessej

49

geliştirdiğim ve diğerlerinden çok daha kararlı bir çözüm:

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
bu da url'yi parçalara ayırmanızı gerektirir. Bir bilgisayarın URL'nin hangi bölümünün kodlanacağını bilmesi mümkün değildir. Yukarıdaki düzenlememi görün
fmucar

4
@fmucar Bu kod parçası için teşekkürler! Bunun UTF-8 olmadığı belirtilmelidir. UTF-8'i almak için girişi buradanString utf8Input = new String(Charset.forName("UTF-8").encode(input).array()); alın ( buradan alınır )
letmaik

1
Bu çözüm aslında "http: //" bölümünü "http% 3A% 2F% 2F" ye kodlar, bu da ilk sorunun kaçınmaya çalıştığı şeydir.
Benjamin Piette

2
URL'nin tamamını değil, yalnızca kodlamanız gerekenleri iletirsiniz. Bir URL dizesinin tamamını iletmenin ve doğru kodlamayı beklemenin bir yolu yoktur. Her durumda, URL'yi mantıksal parçalarına ayırmanız gerekir.
fmucar

2
UTF-8'e güvensiz karakterleri kodlamadığı için bu cevapla ilgili problemlerim vardı .. yine de akran uygulamasına bağlı olabilir.
Tarnschaf

36

Bir URL'niz varsa, url.toString () yöntemini bu yönteme aktarabilirsiniz. İlk kod çözme, çift kodlamayı önlemek için (örneğin, bir boşluğu kodlamak% 20 ile sonuçlanır ve yüzde işaretini kodlamak% 25 ile sonuçlanır, bu nedenle çift kodlama bir boşluğu% 2520'ye dönüştürür). Ardından, URL'nin tüm bölümlerini ekleyerek (sorgu parametrelerini düşürmemeniz için) yukarıda açıklandığı gibi URI'yi kullanın.

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
Dizeyi " google.co.in/search?q=123%!123 " olarak ilettiğinizde URLDecoder.decode (dize, "UTF-8") bir IllegalArgumentException ile başarısız olur . Bu geçerli bir URL. Sanırım% kodlama karakteri yerine veri olarak kullanıldığında bu API çalışmaz.
MediumOne

26

Evet, URL kodlaması bu dizeyi bir URL'de düzgün bir şekilde son hedefe geçirilecek şekilde kodlayacaktır. Örneğin, http://stackoverflow.com?url=http://yyy.com adresine sahip olamazsınız . UrlEnco parametresi, bu parametre değerini düzeltir.

Bu yüzden sizin için iki seçeneğim var:

  1. Alan adından ayrı yola erişiminiz var mı? Eğer öyleyse yolu UrlEncode ile yapabilirsiniz. Ancak, durum böyle değilse, seçenek 2 sizin için olabilir.

  2. Müşterekler-httpclient-3.1. Bu bir sınıf URIUtil vardır:

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

Bu, yalnızca URI'nin yol bölümünü kodlayacağından tam olarak aradığınızı verir.

Bilginize, bu yöntemin çalışma zamanında çalışması için commons-codec bileşenine ve commons günlüğüne ihtiyacınız olacaktır.


Sidenote apache commons, görünüşe göre 4.x dallarında URIUtil'i korumayı bıraktı, bunun yerine JDK'nın URI sınıfını kullanmanızı tavsiye etti. Sadece ipi kendiniz kırmanız gerektiği anlamına gelir.
Nicholi

2) Kesinlikle burada da tavsiye edilir stackoverflow.com/questions/5330104/… Ben de URIUtilçözüm kullandım
Kra

11

Nitpicking: tanım gereği boşluk karakteri içeren bir dize bir URI değildir. Yani aradığınız şey , RFC 3986 Bölüm 2.1'de tanımlanan URI çıkışını uygulayan koddur .


Cevaplarda “nasıl” değil, “ne” ye ihtiyacımız var.
shinzou

11

Maalesef org.apache.commons.httpclient.util.URIUtilkullanımdan kaldırıldı ve kodlar replacement org.apache.commons.codec.net.URLCodecgerçek URL'lerde değil form gönderileri için uygun mu? Bu yüzden tek bir bileşen (? 'Ve' s olan tüm sorgu dizeleri için uygun değil) kendi işlevimi yazmak zorunda kaldım

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

Hadi, bunu yapan bir kütüphane olmalı.
shinzou

9

URLEncoding, ne yazık ki keşfettiğiniz gibi HTTP URL'lerini iyi kodlayabilir. " Http://search.barnesandnoble.com/booksearch/first book.pdf" ilettiğiniz dize , doğru ve tamamen URL kodlu bir forma kodlandı. Bir URL'de parametre olarak geri döndüğünüz tüm uzun gobbledigook dizesini geçirebilirsiniz ve tam olarak geçtiğiniz dizeye deşifre edilebilir.

URL'nin tamamını parametre olarak iletmekten biraz farklı bir şey yapmak istediğiniz anlaşılıyor. Topladığım kadarıyla, " http://search.barnesandnoble.com/booksearch/whateverTheUserPassesIn " gibi görünen bir arama URL'si oluşturmaya çalışıyorsunuz . Kodlamanız gereken tek şey "whateverTheUserPassesIn" bitidir, bu yüzden belki de tek yapmanız gereken şudur:

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

Bu sizin için daha geçerli bir şey üretmelidir.


17
Bu, userInput içindeki boşlukların yerine "+" yazar. Afiş, "% 20" ile değiştirilmelidir.
vocaro

@vocaro: bu çok iyi bir nokta. URLEncoder, bağımsız değişkenler URL'nin geri kalanı gibi değil sorgu parametreleriyken kaçar.
Brandon Yarbrough

9

Kimse projelerine bağımlılık eklemek istemiyorsa, bu işlevler yardımcı olabilir.

URL'mizin 'yol' bölümünü buraya geçiriyoruz. Muhtemelen tam URL'yi parametre olarak iletmek istemezsiniz (sorgu dizelerinin farklı çıkış karakterleri vb. Gerekir).

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

Ve testler:

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

}

Bunun için teşekkürler, ancak bir alanı kodlamak için ne yapmam gerekiyor - örneğinize göre% 20 kullanın?
N00b Pr0grammer

% 20
Cuga

7

URL'nizde kodlanmış bir "/" (% 2F) varsa hala bir sorun vardır.

RFC 3986 - Bölüm 2.2 şunları söylüyor: "Bir URI bileşenine ilişkin veriler, ayrılmış bir karakterin sınırlayıcı olarak amacıyla çakışırsa, çakışan verilerin URI oluşturulmadan önce yüzde olarak kodlanması gerekir." (RFC 3986 - Bölüm 2.2)

Ancak Tomcat ile ilgili bir Sorun var:

http://tomcat.apache.org/security-6.html - Apache Tomcat 6.0.10'da düzeltildi

önemli: Dizin geçişi CVE-2007-0450

Tomcat '\', '% 2F' ve '% 5C' [...] 'e izin verir.

Aşağıdaki Java sistem özellikleri, URL'lerde yol sınırlayıcıların işlenmesinde ek kontrol sağlamak için Tomcat'e eklenmiştir (her iki seçenek de varsayılan olarak false değerine ayarlanmıştır):

  • org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH: doğru | yanlış
  • org.apache.catalina.connector.CoyoteAdapter.ALLOW_BACKSLASH: doğru | yanlış

Tüm URL'lerin proxy sunucularında olduğu gibi Tomcat tarafından ele alınmasının garanti edilememesi nedeniyle, Tomcat her zaman proxy erişimi kısıtlayıcı bağlam erişimi kullanılmamış gibi güvence altına alınmalıdır.

Etkiler: 6.0.0-6.0.9

Dolayısıyla,% 2F karakterine sahip bir URL'niz varsa Tomcat şunu döndürür: "400 Geçersiz URI: noSlash"

Hata düzeltmesini Tomcat başlangıç ​​komut dosyasında değiştirebilirsiniz:

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

7

Önceki cevapları kendi yöntemimi yazmak için okudum, çünkü önceki cevapların çözümünü kullanarak düzgün çalışan bir şey bulamadım, benim için iyi görünüyor, ancak bununla çalışmayan URL'yi bulabilirseniz, lütfen bana bildirin.

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

Matt ile aynı fikirdeyim. Aslında, öğreticilerde iyi açıklandığını hiç görmedim, ancak bir mesele URL yolunun nasıl kodlanacağı ve çok farklı bir URL'nin (sorgu kısmı, arkasındaki "? "sembolü). Benzer kodlama kullanırlar, fakat aynı değildir.

Özellikle beyaz boşluk karakterinin kodlanması için. URL yolunun% 20 olarak kodlanması gerekirken sorgu kısmı% 20 ve "+" işaretine izin verir. En iyi fikir, bir Web tarayıcı kullanarak Web sunucumuza karşı kendimiz test etmektir.

Her iki durumda da, HER ZAMAN BİLEŞENİ BİLEŞENİ kodlar , asla tüm dizeyi kodlamaz . Gerçekten URLEncoder sorgu kısmı için izin verir. Yol parçası için sınıf URI'sini kullanabilirsiniz, ancak bu durumda tek bir bileşen değil, tüm dizeyi ister.

Her neyse, bu problemlerden kaçınmanın en iyi yolunun, kişisel, çelişkili olmayan bir tasarım kullanmak olduğuna inanıyorum . Nasıl? Örneğin, dizinleri veya parametreleri asla aZ, AZ, 0-9 ve _ dışındaki karakterleri kullanarak adlandırmam. Bu şekilde, tek gereksinim her parametrenin değerini kodlamaktır, çünkü bir kullanıcı girişinden gelebilir ve kullanılan karakterler bilinmemektedir.


2
sorudaki URL'yi kullanan örnek kod cevabınızı koymak için iyi bir şey olacaktır
Martin Serrano


3

GUAVAEscaper'ı da kullanabilir ve yollayabilirsiniz: UrlEscapers.urlFragmentEscaper().escape(relativePath)


2

Carlos Heuberger'in cevabına ek olarak: varsayılandan (80) farklı bir şey gerekiyorsa, 7 param yapıcı kullanılmalıdır:

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

Yukarıdaki içeriği aldım ve biraz değiştirdim. Ben ilk önce pozitif mantığı seviyorum ve bir HashSet bir String üzerinden arama gibi diğer bazı seçeneklerden daha iyi performans verebilir düşündüm. Her ne kadar, otomatik boks cezasının buna değip değmeyeceğinden emin değilim, ancak derleyici ASCII karakterleri için optimize ederse, boks maliyeti düşük olacaktır.

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

Aşağıdaki standart Java çözümünü kullanın ( Web Plattform Tests tarafından sağlanan test senaryolarının yaklaşık 100'ünü geçer ):

0. URL'nin zaten kodlanmış olup olmadığını test edin .

1. URL'yi yapısal parçalara ayırın. Bunun için kullanın java.net.URL .

2. Her yapısal parçayı uygun şekilde kodlayın!

3. Ana makine adını kodlamak IDN.toASCII(putDomainNameHere)için Punycode kullanın !

4.java.net.URI.toASCIIString() Yüzde kodlamak için kullanın , NFC kodlu unicode - (daha iyi NFKC olurdu!).

Burada daha fazlasını bulabilirsiniz: https://stackoverflow.com/a/49796882/1485527


0

HTTP URL'leri oluşturmanıza yardımcı olacak yeni bir proje oluşturdum. Kitaplık, yol parçalarını ve sorgu parametrelerini otomatik olarak URL kodlar.

Kaynağı görüntüleyebilir ve https://github.com/Widen/urlbuilder adresinden bir ikili dosya indirebilirsiniz.

Bu sorudaki örnek URL:

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

üretir

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


0

Ben de aynı problemi yaşadım. Bunu çözerek çözdü:

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

Dizeyi kodlar ancak ":" ve "/" kelimelerini atlar.


0

Bunu kullanıyorum

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

bu bağımlılığı ekle

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

-2

Bu amaca hizmet eden bir kütüphane geliştiriyorum: galimatias . URL'yi web tarayıcılarının yaptığı gibi ayrıştırır. Yani, bir URL bir tarayıcıda çalışırsa, galimatias tarafından doğru şekilde ayrıştırılır .

Bu durumda:

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

Size verecek: http://search.barnesandnoble.com/booksearch/first%20book.pdf. Tabii ki bu en basit durum, ama ötesinde bir şeyle çalışacak java.net.URI.

Şuradan kontrol edebilirsiniz: https://github.com/smola/galimatias


-3

Bunun gibi bir işlev kullanabilirsiniz. Tamamlayın ve ihtiyaçlarınıza göre değiştirin:

/**
     * 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", "&");
    }

Kullanım örneği:

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

Sonuç şudur: http://www.growup.com/folder/int%C3%A9rieur-%C3%A0_vendre?o=4


1
Bu cevap URLCodec olmadan tamamlanmamıştır.
Lorne Marquis

.replace () zincirleme için oy verin, ideal değil ama temel geçici kullanım durumları için yeterli
svarog


-7

Nasıl olur:

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, geçersiz URL karakterlerinden kaçmak için kullanılamaz. Sadece formları kodlamak için.
Okçu
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.