Кодирование параметров запроса URL в Java

109

Как кодировать параметры запроса для перехода по URL-адресу в Java? Я знаю, это кажется очевидным и уже заданным вопросом.

Есть две тонкости, в которых я не уверен:

  1. Следует ли кодировать пробелы в URL-адресе как «+» или «% 20»? В Chrome, если я ввожу "http://google.com/foo=?bar me", Chrome изменяет его на кодировку% 20
  2. Необходимо / правильно ли кодировать двоеточия ":" как% 3B? Chrome этого не делает.

Ноты:

  • java.net.URLEncoder.encodeпохоже, не работает, похоже, для отправки данных кодирования. Например, он кодирует пробел +вместо %20и кодирует двоеточие, в котором нет необходимости.
  • java.net.URI не кодирует параметры запроса
Алекс Блэк
источник
Этот вопрос выглядит полезным: stackoverflow.com/questions/444112/…
Alex Black
2
структура части запроса зависит от сервера, хотя большинство ожидают application/x-www-form-urlencodedпары ключ / значение. Подробнее см. Здесь: незаконныйargumentexception.blogspot.com/2009/12/…
МакДауэлл,

Ответы:

128

java.net.URLEncoder.encode(String s, String encoding)тоже может помочь. Он следует кодировке HTML-формы application/x-www-form-urlencoded.

URLEncoder.encode(query, "UTF-8");

С другой стороны, процентное кодирование (также известное как кодирование URL ) кодирует пробел с помощью %20. Двоеточие - это зарезервированный символ, поэтому :после кодирования останется двоеточием.

Бухаке Синди
источник
3
Я упомянул, что не думал, что это кодирует URL-адрес, вместо этого он кодирует данные, которые должны быть отправлены через форму. Комментарии?
Alex Black
Это потому, что URLEncoderон соответствует application/x-www-form-urlencodedформату MIME (который является допустимой кодировкой HTML-формы). Я предполагаю, что это не то, что вы ищете.
Buhake Sindi
6
В итоге я использовал URLEncoder.encode и заменил «+» на «% 20»
Alex Black
2
Он кодирует косые черты в "% 2F", не следует ли оставлять косые черты URL такими, какие они есть?
golimar
6
@golimar Нет, не должно. Вы должны указывать только значение параметра, а не весь URL-адрес. Рассмотрим пример http://example.com/?url=http://example.com/?q=c&sort=name. Кодировать &sort=nameили нет? Невозможно отличить значение от URL-адреса. Это точная причина, по которой вам вообще нужно кодирование значений.
Pijusn
15

РЕДАКТИРОВАТЬ: URIUtilбольше не доступен в более поздних версиях, лучше ответьте на Java - закодируйте URL-адрес или г-н Синди в этой теме.


URIUtilApache httpclient действительно полезен, хотя есть несколько альтернатив

URIUtil.encodeQuery(url);

Например, он кодирует пробел как «+» вместо «% 20».

И то, и другое совершенно справедливо в правильном контексте . Хотя, если вы действительно предпочитаете, вы можете заменить строку.

Йохан Сьёберг
источник
Я должен был бы согласиться. Используйте HttpClient, вы будете намного счастливее.
DaShaun
Выглядит многообещающе, случайно попала в ссылку? Я ищу в Google, но нахожу много.
Alex Black
1
Кажется, этого метода нет в HttpClient 4.1? hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/org/…
Alex Black
@Alex, хм, это раздражает, я всегда использовал этот распорядок с хорошими результатами. Одна из идей состоит в том, чтобы взять исходный код из 3-го выпуска, поскольку теперь они явно не хотели его больше поддерживать.
Johan Sjöberg
1
URIUtil.encodeWithinQueryэто то, что вы бы использовали для кодирования отдельного параметра запроса, что, по-видимому, и задавал исходный вопрос.
Джесси Глик
13

К сожалению, URLEncoder.encode () не дает допустимого процентного кодирования (как указано в RFC 3986 ).

URLEncoder.encode () кодирует все отлично, за исключением того, что пробел кодируется как "+". Все кодировщики Java URI, которые мне удалось найти, предоставляют только общедоступные методы для кодирования запроса, фрагмента, частей пути и т. Д., Но не раскрывают "исходную" кодировку. Это прискорбно, поскольку фрагменту и запросу разрешено кодировать пробел в +, поэтому мы не хотим их использовать. Путь закодирован правильно, но сначала «нормализуется», поэтому мы не можем использовать его и для «общего» кодирования.

Лучшее решение, которое я мог придумать:

return URLEncoder.encode(raw, "UTF-8").replaceAll("\\+", "%20");

Если replaceAll()это слишком медленно для вас, я думаю, альтернатива - накрутить собственный кодировщик ...

РЕДАКТИРОВАТЬ: Сначала у меня был этот код, который неправильно кодирует "?", "&", "=":

//don't use - doesn't properly encode "?", "&", "="
new URI(null, null, null, raw, null).toString().substring(1);
Коста
источник
+- совершенно правильная кодировка пробела.
Лоуренс Доль,
@LawrenceDol, это правда, но иногда +может неправильно интерпретироваться - взгляните на C # blogs.msdn.microsoft.com/yangxind/2006/11/08/…
Lu55,
Это. Я сравнил различные альтернативы с encodeURIComponentвыводом метода Javascript , и это было единственное точное совпадение с теми, которые я пробовал (запросы с пробелами, турецкими и немецкими специальными символами).
Утку Оздемир
8

Нет необходимости кодировать двоеточие в запросе как% 3B, хотя это не является незаконным.

URI         = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
query       = *( pchar / "/" / "?" )
pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
pct-encoded   = "%" HEXDIG HEXDIG
sub-delims    = "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / ";" / "="

Также кажется, что допустимы только пробелы с процентной кодировкой, поскольку я сомневаюсь, что пробел - это АЛЬФА или ЦИФРА.

обратитесь к спецификации URI для получения более подробной информации.

Эдвин Бак
источник
Но это может изменить значение URI, поскольку интерпретация строки запроса зависит от сервера. Если вы создаете application/x-www-form-urlencodedстроку запроса, все в порядке. Если вы исправляете URL-адрес, введенный / вставленный пользователем, его :следует оставить в покое.
тк.
@tc. Вы правы, если двоеточие используется как общий разделитель (стр. 12 RFC); однако, если он не используется в качестве общего разделителя, тогда обе кодировки должны разрешаться одинаково.
Эдвин Бак
Вы также должны быть осторожны, поскольку URL-адреса на самом деле не являются подмножеством URI: adamgent.com/post/25161273526/urls-are-not-a-subset-of-uris
Адам Гент
5

Встроенный Java URLEncoder делает то, что должен, и вы должны его использовать.

А «+» или «% 20» являются обеими действительной для замены пробела в URL. Любой из них будет работать.

Знак «:» должен быть закодирован, так как это символ-разделитель. т.е. http: // foo или ftp: // bar . Тот факт, что конкретный браузер может обрабатывать его, когда он не закодирован, не делает его правильным. Вы должны их закодировать.

Рекомендуется использовать метод, который принимает параметр кодировки символов. Здесь обычно используется UTF-8, но вы должны указать его явно.

URLEncoder.encode(yourUrl, "UTF-8");
rfeak
источник
5
+это только представление пространства в application/x-www-form-urlencoded; не гарантируется работа даже при ограничении HTTP. Точно так же :это допустимо в строке запроса и не должно преобразовываться в %3B; сервер может интерпретировать их по-разному.
тк.
1
этот метод также кодировать целые URL - адрес слэш и другие символы , которые являются частью , например , http://для http%3A%2F%2Fкоторых не является правильным
Для Кра
2
@ToKra, вы не должны кодировать http://деталь. Метод предназначен для параметров запроса и данных закодированной формы. Однако, если вы хотите передать URL-адрес другого веб-сайта в качестве параметра запроса, ЗАТЕМ вы захотите его закодировать, чтобы не запутать парсер URL.
beldaz
@tc По моему мнению, w3.org/TR/html4/interact/forms.html#h-17.13.3.3 все данные формы GET закодированы как application/x-www-form-urlencodedтип содержимого. Разве это не значит, что он должен работать с HTTP?
beldaz
0

если у вас есть только проблема с пробелом в URL-адресе. Я использовал код ниже, и он отлично работает

String url;
URL myUrl = new URL(url.replace(" ","%20"));

пример: url

www.xyz.com?para=hello, сэр

тогда вывод muUrl

www.xyz.com?para=hello%20sir

Джигнеш Патель
источник
0
String param="2019-07-18 19:29:37";
param="%27"+param.trim().replace(" ", "%20")+"%27";

Я заметил, что в случае Datetime (Timestamp) URLEncoder.encode(param,"UTF-8")не работает.

ICL Sales EXIMON
источник