URLEncoder не умеет переводить символы пробела - PullRequest
158 голосов
/ 19 января 2011

Я ожидаю

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

для вывода:

Hello%20World

(20 - шестнадцатеричный код ASCII для пробела)

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

Hello+World

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

Ответы [ 14 ]

205 голосов
/ 19 января 2011

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

Из javadocs :

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

и из спецификации HTML :

application / x-www-form-urlencoded

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

  1. Контрольимена и значения экранированы.Символы пробела заменяются на `+ '

Вам придется заменить его, например:

System.out.println(java.net.URLEncoder.encode("Hello World", "UTF-8").replace("+", "%20"));
44 голосов
/ 23 июля 2015

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

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

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, это будет только кодировать пространство.Вместо этого используйте библиотеку.

25 голосов
/ 19 января 2011

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

От Javadoc:

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

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

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

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 " %$&+,/:;=?@<>#%".indexOf(ch) >= 0;
 }
11 голосов
/ 19 января 2011

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 голосов
/ 09 марта 2018

Другие ответы либо представляют собой ручную замену строки, URLEncoder , которая фактически кодирует для формата HTML, Apache брошенный URIUtil , либо использование Guava's UrlEscapers . Последний вариант в порядке, за исключением того, что он не обеспечивает декодер.

Apache Commons Lang предоставляет URLCodec , который кодирует и декодирования в соответствии с форматом URL rfc3986 .

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

Если вы уже используете Spring, вы также можете выбрать его UriUtils класс.

4 голосов
/ 19 января 2011

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

2 голосов
/ 12 сентября 2017

Только что боролся с этим на Android, ему удалось наткнуться на Uri.encode (String, String), в то время как специфический для android (android.net.Uri) может быть полезен для некоторых.

статическое строковое кодирование (String s, String allow)

https://developer.android.com/reference/android/net/Uri.html#encode(java.lang.String, java.lang.String)

2 голосов
/ 07 августа 2015

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

org.apache.catalina.util.URLEncoder ul = new org.apache.catalina.util.URLEncoder().encode("MY URL");
1 голос
/ 03 августа 2018

Хотя довольно старый, тем не менее быстрый ответ:

Spring предоставляет UriUtils - с его помощью вы можете указать, как кодировать и с какой частью это связано с URI, например,

encodePathSegment
encodePort
encodeFragment
encodeUriVariables
....

Я использую их, потому что мы уже используем Spring, т.е. дополнительная библиотека не требуется!

...