URLEncoder не способен переводить символ пробела

Я ожидаю

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

для вывода:

Hello%20World

(20 - это код ASCII Hex для пробела)

Однако, я получаю:

Hello+World

Использую ли я неправильный метод? Каков правильный метод, который я должен использовать?

Ответ 1

Это ведет себя так, как ожидалось. URLEncoder реализует спецификации HTML для кодирования URL-адресов в форматах HTML.

Из javadocs:

Этот класс содержит статические методы для преобразование строки в application/x-www-form-urlencoded MIME Формат.

и Спецификация HTML:

application/x-www-form-urlencoded

Формы, представленные с этим типом контента должен быть закодирован следующим образом:

  • Управляющие имена и значения экранируются. Символы места заменены по `+ '

Вам нужно будет заменить его, например:

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

Ответ 2

Этот класс выполняет кодировку типа application/x-www-form-urlencoded, а не процентное кодирование, поэтому замена на + является правильным поведением.

Из javadoc:

При кодировании String применяются следующие правила:

  • Буквенно-цифровые символы "a" через "z", "A" через "Z" и "0" - "9" остаются неизменными.
  • Специальные символы ".", "-", "*" и "_" остаются неизменными.
  • Символ пробела "преобразуется в знак плюса" + ".
  • Все остальные символы небезопасны и сначала преобразуются в один или несколько байтов, используя некоторую схему кодирования. Затем каждый байт представлен 3-символьной строкой" % xy", где xy - двухзначное шестнадцатеричное представление байта. Рекомендуемой схемой кодирования для использования является UTF-8. Однако по соображениям совместимости, если кодировка не указана, используется кодировка по умолчанию платформы.

Ответ 3

Пространство кодируется в %20 в URL-адресах и + в формах переданных данных (приложение типа контента /x -www-form-urlencoded). Вам нужен первый.

Использование Guava:

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

Вы можете использовать UrlEscapers:

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

Не используйте String.replace, это будет только кодировать пробел. Вместо этого используйте библиотеку.

Ответ 4

Hello+World заключается в том, как браузер будет кодировать данные формы (application/x-www-form-urlencoded) для запроса GET, и это общепринятая форма для части запроса URI.

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

Если вы отправили этот запрос на сервлет Java, сервлет правильно декодировал значение параметра. Обычно единственное время, когда возникают проблемы, заключается в том, что кодировка не соответствует.

Строго говоря, в спецификациях HTTP или URI нет требования о том, чтобы часть запроса была закодирована с использованием application/x-www-form-urlencoded пар ключ-значение; часть запроса просто должна быть в форме, которую принимает веб-сервер. На практике это вряд ли будет проблемой.

Как правило, было бы неправильно использовать эту кодировку для других частей URI (например, путь). В этом случае вы должны использовать схему кодирования, как описано в RFC 3986.

http://host/Hello%20World

Подробнее здесь.

Ответ 5

Кодировать параметры запроса

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

ИЛИ, если вы хотите избежать символов в URI

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 " %$&+,/:;[email protected]<>#%".indexOf(ch) >= 0;
 }

Ответ 6

"+" является правильным. Если вам действительно нужно %20, то впоследствии замените Плюсы.

Ответ 7

Проверьте класс java.net.URI.

Ответ 8

ИСПОЛЬЗОВАТЬ MyUrlEncode.URLencoding(String url, String enc), чтобы справиться с проблемой

    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

Это сработало для меня

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

Ответ 11

Использую ли я неправильный метод? Каков правильный метод, который я должен использовать?

Да, этот метод java.net.URLEncoder.encode не был сделан для преобразования "в" 20% "в соответствии со спецификацией ( source).

Символ пробела "преобразуется в знак плюса" +".

Даже это не правильный метод, вы можете изменить это: System.out.println(java.net.URLEncoder.encode("Hello World", "UTF-8").replaceAll("\\+", "%20")); иметь хороший день =).

Ответ 12

используйте набор символов "ISO-8859-1" для URLEncoder