URLEncoder boşluk karakterini çeviremiyor


179

bekliyorum

System.out.println(java.net.URLEncoder.encode("Hello World", "UTF-8"));

ÇIKTI:

Hello%20World

(20 boşluk için ASCII Hex kodudur)

Ancak, ne olsun:

Hello+World

Yanlış yöntemi mi kullanıyorum? Kullanmam gereken doğru yöntem nedir?


3
sınıf adı gerçekten kafa karıştırıcı ve birçok kişi yanlış kullanmış. ancak fark etmezler, çünkü URLDecoder uygulandığında orijinal değer geri yüklenir, bu nedenle + veya% 20 gerçekten onlar için önemli değildir.
irreputable

Yanıtlar:


227

Bu beklendiği gibi davranır. URLEncoderUygular HTML formlarında nasıl encode URL'ler için HTML Özellikleri.

Gönderen javadocs :

Bu sınıf, bir String'i application / x-www-form-urlencoded MIME biçimine dönüştürmek için statik yöntemler içerir.

ve HTML Spesifikasyonundan :

Uygulama / x-www-form-urlencoded

Bu içerik türüyle gönderilen formlar aşağıdaki gibi kodlanmalıdır:

  1. Kontrol adları ve değerleri kaçtı. Boşluk karakterleri `` + '' ile değiştirilir

Değiştirmeniz gerekecek, örneğin:

System.out.println(java.net.URLEncoder.encode("Hello World", "UTF-8").replace("+", "%20"));

19
iyi Bu gerçekten bir cevap, yerine bir java kütüphane ya da görevi yerine getirmek için bir işlev var mı?
co2f2e

5
Artı işaretinin kaçması gerekiyort.println(java.net.URLEncoder.encode("Hello World", "UTF-8").replace("\\+", "%20"));
George

26
@congliu bu yanlış - muhtemelen regex ile çalışan replaceAll () yöntemini düşünüyorsunuz - replace () basit karakter dizisinin değiştirilmesidir.
CupawnTae

12
Evet @congliu iyi yol: URLEncoder.encode ("Myurl", "utf-8"). ReplaceAll ("\\ +", "% 20");
eento

9
@ClintEastwood Bu yanıt, asıl sorulanın işini yapmayan java.net.URLEncoder'ın kullanılmasını teşvik eder. Ve böylece bu cevap, üstüne replace () kullanarak bir yama önermektedir. Neden olmasın? Çünkü bu çözüm hata eğilimli ve farklı bir karakterle 20 benzer soruya yol açabilir. Bu yüzden bunun dar görüşlü olduğunu söyledim.
17'de pyb

57

Bir alan, %20URL'lerde ve +gönderilen formlarda (içerik türü application / x-www-form-urlencoded) olarak kodlanır . İlkine ihtiyacınız var.

Guava'yı kullanma :

dependencies {
     compile 'com.google.guava:guava:23.0'
     // or, for Android:
     compile 'com.google.guava:guava:23.0-android'
}

UrlEscapers'ı kullanabilirsiniz :

String encodedString = UrlEscapers.urlFragmentEscaper().escape(inputString);

String.replace kullanmayın, bu yalnızca alanı kodlar. Bunun yerine bir kütüphane kullanın.


Ayrıca Android için çalışır, com.google.guava: guava: 22.0-rc1-android.
Bevor

1
@Bevor rc1, 1. Sürüm Adayı, yani henüz genel sürüm için onaylanmamış bir sürüm anlamına gelir. Mümkünse, hata içerdiği bilinen anlık görüntü, alfa, beta, rc olmayan bir sürüm seçin.
pyb

1
@pyb Teşekkürler, ancak projem bittiğinde kütüphaneleri yine de güncelleyeceğim. Yani, son sürümleri olmadan eşyaya gitmeyeceğim. Ve hala çok hafta sürüyor, bu yüzden sanırım son bir versiyon var.
Bevor

1
Maalesef Guava, Apache'nin URLCodec'inden farklı bir kod çözücü sağlamaz .
Benny Bottema

26

Bu sınıf yerine application/x-www-form-urlencodednedenle değiştirilmesi yerine yüzde kodlamaya göre kodlayan tipi ile +doğru bir davranıştır.

Javadoc'tan:

Bir Dizeyi kodlarken aşağıdaki kurallar geçerlidir:

  • "A" - "z", "A" - "Z" ve "0" - "9" arasındaki alfasayısal karakterler aynı kalır.
  • ".", "-", "*" ve "_" özel karakterleri aynı kalır.
  • "" Boşluk karakteri, artı işaretine "+" dönüştürülür.
  • Diğer tüm karakterler güvensizdir ve önce bazı kodlama şeması kullanılarak bir veya daha fazla bayta dönüştürülür. Daha sonra her bayt, 3 karakterlik "% xy" dizesi ile temsil edilir; burada xy, baytın iki basamaklı onaltılı gösterimidir. Kullanılması önerilen kodlama şeması UTF-8'dir. Bununla birlikte, uyumluluk nedeniyle, bir kodlama belirtilmezse, platformun varsayılan kodlaması kullanılır.

@axtavt Güzel bir açıklama. Ama hala bazı sorularım var. İçinde urlmekan olarak yorumlanmalıdır %20. Yani yapmamız gerek url.replaceAll("\\+", "%20")? Ve eğer javascript ise, escapefonksiyonu kullanmamalıyız . Kullanın encodeURIveya encodeURIComponentbunun yerine. Bende böyle düşünmüştüm.
Alston

1
@Stallman bu JavaScript, JavaScript değil. Tamamen farklı diller.
Charles Wood

19

Sorgu parametrelerini kodlama

org.apache.commons.httpclient.util.URIUtil
    URIUtil.encodeQuery(input);

VEYA URI içindeki karakterlerden kaçmak istiyorsanız

public static String escapeURIPathParam(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
Kullanımı org.apache.commons.httpclient.util.URIUtilsorunu çözmenin en etkili yolu gibi görünüyor!
Stéphane Ammar

11

Hello+Worldtarayıcının application/x-www-form-urlencodedbir GETistek için form verilerini ( ) nasıl kodlayacağıdır ve bu, bir URI'nin sorgu kısmı için genellikle kabul edilen formdur.

http://host/path/?message=Hello+World

Bu isteği bir Java sunucu uygulamasına gönderirseniz, sunucu uygulaması parametre değerinin kodunu çözecektir. Genellikle burada sorun olan tek zaman kodlamanın eşleşmemesi.

Kesin olarak, HTTP veya URI özelliklerinde, sorgu parçasının application/x-www-form-urlencodedanahtar / değer çiftleri kullanılarak kodlanmasına gerek yoktur ; sorgu bölümünün sadece web sunucusunun kabul ettiği biçimde olması gerekir. Uygulamada, bunun bir sorun olması pek olası değildir.

Bu kodlamanın URI'nin diğer bölümleri için kullanılması genellikle yanlış olur (örneğin yol). Bu durumda, kodlama şemasını RFC 3986'da açıklandığı gibi kullanmalısınız .

http://host/Hello%20World

Daha burada .


5

Diğer cevaplar ya manuel dize değiştirme, aslında HTML formatını kodlayan URLEncoder , Apache'nin terk edilmiş URIUtil'i ya da Guava UrlEscapers'ı kullanıyor . Sonuncusu iyidir, ancak bir kod çözücü sağlamaz.

Apache Commons Lang, rfc3986 URL biçimine göre kodlayan ve kod çözen URLCodec'i sağlar .

String encoded = new URLCodec().encode(str);
String decoded = new URLCodec().decode(str);

Zaten bahar kullanıyorsanız, ayrıca kullanmayı seçebilirler onun UriUtils sınıfını da .


6
URLCodec burada boşlukları artı olarak kodladığı için iyi bir çözüm değildir, ancak soru boşlukların% 20 olarak kodlanmasını istemektedir.
davidwebster48

3

"+" doğrudur. Gerçekten% 20'ye ihtiyacınız varsa, daha sonra Plusses'i kendiniz değiştirin.


5
İlk dize gerçekten bir + karakteri içeriyorsa bir sorun olabilir.
Alexis Dufrenoy

17
@Traroth - Pek değil. +Orijinal metindeki bir karakterin olarak kodlanması gerekir %2B.
Ted Hopp

+bağlamı bilmeden bunun doğru olduğunu söylemek en azından bilgiçlik taslayan. Downvoted. + Veya% 20'nin ne zaman kullanılacağını öğrenmek için diğer yanıtları okuyun.
Clint Eastwood

@ClintEastwood: Boşluklara ilişkin + karakterinin URL'lerde doğru olmaması nedeniyle bana herhangi bir kullanımdan bahsedebilir misiniz? Diğer tarafta uygun olmayan bir URL ayrıştırıcısı hariç?
Daniel

@ Emin, "yanlış" demiyor ama uygun değil mi? Evet. Analytics araçları genellikle, "+" gibi belirli bir karakterle ayrılmış değerlere sahip sorgu parametreleri kullanır. Bu durumda, "% 20" yerine "+" kullanmak yanlış olur. Bir formdaki boşluklardan kaçmak için "+" kullanılırken, "yüzde kodlaması" (URL kodlaması olarak da bilinir) URL'lere daha fazla yöneliktir.
Clint Eastwood


2

Bu benim için çalıştı

org.apache.catalina.util.URLEncoder ul = new org.apache.catalina.util.URLEncoder().encode("MY URL");

1

Oldukça eski olmasına rağmen, yine de hızlı bir yanıt:

Bahar UriUtils sağlar - bununla nasıl kodlanacağını ve hangi bölümün bir URI'den ilişkili olduğunu belirtebilirsiniz, ör.

encodePathSegment
encodePort
encodeFragment
encodeUriVariables
....

Onları kullanıyorum çünkü zaten Spring kullanıyoruz, yani ek kütüphaneye gerek yok!



0

Yanlış yöntemi mi kullanıyorum? Kullanmam gereken doğru yöntem nedir?

Evet, bu yöntem java.net.URLEncoder.encode "(" ) özelliğine ( kaynağa ) göre "%" değerine dönüştürülmek için yapılmadı .

"" Boşluk karakteri, artı işaretine "+" dönüştürülür.

Bu doğru yöntem olmasa bile, bunu şu şekilde değiştirebilirsiniz: System.out.println(java.net.URLEncoder.encode("Hello World", "UTF-8").replaceAll("\\+", "%20"));iyi günler =).


Yeterli olmayan ( URLEncoder.encode) bir yöntem kullanmanızı ve replaceAllyalnızca bu özel durumda çalışacak şekilde yama eklemenizi öneririz. Bunun yerine doğru sınıfı ve yöntemi kullanın, diğer yanıtlara bakın.
pyb

@pyb, ne yazdığımı anlayamayacağınıza benziyor. Asla "kullanmanızı öneririm" demedim, "yapabilirsin" dedim. Lütfen yazmadan önce okuyun ve anlayın.
Pregunton

Bu, insanların sohbet ettiği normal bir mesaj panosu değil, bir soru ve cevap web sitesidir. Yan yorumlarınız varsa yorumları kullanın. Daha uzun konuşma? Sohbeti kullanın. Kabul etmediğiniz kodu yanıt olarak göndermeyin. Lütfen başkalarına katkıda bulunmadan ve ders vermeden önce bu sitenin kurallarını okuyun ve anlayın.
pyb

1
Geriye dönüyorum çünkü diğer çözümlerin çoğu aynı tavsiyeyi veriyor. Bu yöntemin yanlış olduğunu kanıtlayan hiçbir "spesifik vaka" sunulmamıştır. Try-catch blokları veya bağımlılıkları olan apache ortaklarını kullanmak, replaceAll ile etkin bir şekilde yamanabilen bir yöntem için çok zahmetlidir.
Eugene Kartoyev

-2

KULLANIM MyUrlEncode.URLencoding (string url, dize enc) sorunu ele almak

    public class MyUrlEncode {
    static BitSet dontNeedEncoding = null;
    static final int caseDiff = ('a' - 'A');
    static {
        dontNeedEncoding = new BitSet(256);
        int i;
        for (i = 'a'; i <= 'z'; i++) {
            dontNeedEncoding.set(i);
        }
        for (i = 'A'; i <= 'Z'; i++) {
            dontNeedEncoding.set(i);
        }
        for (i = '0'; i <= '9'; i++) {
            dontNeedEncoding.set(i);
        }
        dontNeedEncoding.set('-');
        dontNeedEncoding.set('_');
        dontNeedEncoding.set('.');
        dontNeedEncoding.set('*');
        dontNeedEncoding.set('&');
        dontNeedEncoding.set('=');
    }
    public static String char2Unicode(char c) {
        if(dontNeedEncoding.get(c)) {
            return String.valueOf(c);
        }
        StringBuffer resultBuffer = new StringBuffer();
        resultBuffer.append("%");
        char ch = Character.forDigit((c >> 4) & 0xF, 16);
            if (Character.isLetter(ch)) {
            ch -= caseDiff;
        }
        resultBuffer.append(ch);
            ch = Character.forDigit(c & 0xF, 16);
            if (Character.isLetter(ch)) {
            ch -= caseDiff;
        }
         resultBuffer.append(ch);
        return resultBuffer.toString();
    }
    private static String URLEncoding(String url,String enc) throws UnsupportedEncodingException {
        StringBuffer stringBuffer = new StringBuffer();
        if(!dontNeedEncoding.get('/')) {
            dontNeedEncoding.set('/');
        }
        if(!dontNeedEncoding.get(':')) {
            dontNeedEncoding.set(':');
        }
        byte [] buff = url.getBytes(enc);
        for (int i = 0; i < buff.length; i++) {
            stringBuffer.append(char2Unicode((char)buff[i]));
        }
        return stringBuffer.toString();
    }
    private static String URIEncoding(String uri , String enc) throws UnsupportedEncodingException { //对请求参数进行编码
        StringBuffer stringBuffer = new StringBuffer();
        if(dontNeedEncoding.get('/')) {
            dontNeedEncoding.clear('/');
        }
        if(dontNeedEncoding.get(':')) {
            dontNeedEncoding.clear(':');
        }
        byte [] buff = uri.getBytes(enc);
        for (int i = 0; i < buff.length; i++) {
            stringBuffer.append(char2Unicode((char)buff[i]));
        }
        return stringBuffer.toString();
    }

    public static String URLencoding(String url , String enc) throws UnsupportedEncodingException {
        int index = url.indexOf('?');
        StringBuffer result = new StringBuffer();
        if(index == -1) {
            result.append(URLEncoding(url, enc));
        }else {
            result.append(URLEncoding(url.substring(0 , index),enc));
            result.append("?");
            result.append(URIEncoding(url.substring(index+1),enc));
        }
        return result.toString();
    }

}

9
tekerleği yeniden icat ederek, bir kod tabanına süper hataya açık kod eklemek neredeyse her zaman kötü bir karardır.
Clint Eastwood

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.