Как мне закодировать значения параметров URI?

Я хочу отправить URI в качестве значения параметра запроса / матрицы. Прежде чем я смогу добавить его к существующему URI, мне нужно закодировать его в соответствии с RFC 2396. Например, учитывая ввод:

http://google.com/resource?key=value1 & value2

Ожидаю на выходе:

http%3a%2f%2fgoogle.com%2fresource%3fkey%3dvalue1%2520%26%2520value2

Ни java.net.URLEncoder, ни java.net.URI не будут генерировать правильный результат. URLEncoder предназначен для кодирования HTML-формы, которое отличается от RFC 2396. URI не имеет механизма для кодирования одного значения за раз, поэтому у него нет возможности узнать, что value1 и value2 являются частью одного и того же ключа.


person Community    schedule 14.01.2009    source источник
comment
Не уверен, что понимаю, на какой результат вы рассчитываете. Я бы использовал URLEncoder.   -  person Peter Štibraný    schedule 14.01.2009
comment
Согласно Javadoc для URL: классы URLEncoder и URLDecoder также могут использоваться, но только для кодирования HTML-формы, что не совпадает со схемой кодирования, определенной в RFC2396.   -  person Gili    schedule 14.01.2009
comment
@ Питер: Согласен, но последний мертв. Существует по крайней мере один ответ, за который проголосовало большинство, поэтому он не появится в списке неотвеченных вопросов, даже если ответ технически неверен. Если вы хотите помочь, проголосуйте до нуля.   -  person Gili    schedule 14.01.2009
comment
Интересно, какой будет результат, например, вы дадите свой вопрос.   -  person Peter Štibraný    schedule 14.01.2009
comment
Извините, я удалил свой комментарий о том, что это дубликат stackoverflow .com / questions / 304806 /.   -  person Peter Štibraný    schedule 14.01.2009
comment
@Peter: Я добавил пример ввода и вывода по вашему запросу.   -  person Gili    schedule 14.01.2009
comment
Bugger, Stackoverflow отмечает вопрос как ответ, даже если все ответы имеют нулевую оценку! Пожалуйста, подумайте о голосовании за stackoverflow.uservoice.com/pages/general/suggestions/, чтобы исправить это.   -  person Gili    schedule 14.01.2009
comment
Это похоже на вопрос: Как кодировать параметры URL-адреса?, кроме Java (что один для JavaScript)? Если да, то java.net.URLEncoder - это (или) правильный ответ.   -  person David Balažic    schedule 18.08.2015
comment
@ DavidBalažic Неправильно, я прямо упоминаю, почему URLEncoder не работает в приведенном выше вопросе.   -  person Gili    schedule 18.08.2015


Ответы (7)


UriBuilder Джерси кодирует компоненты URI с помощью приложения / x-www-form-urlencoded и RFC 3986 по мере необходимости. Согласно Javadoc

Методы построителя выполняют контекстное кодирование символов, не разрешенных в соответствующем компоненте URI, в соответствии с правилами типа мультимедиа application / x-www-form-urlencoded для параметров запроса и RFC 3986 для всех других компонентов. Обратите внимание, что кодированию подлежат только символы, не разрешенные в конкретном компоненте, поэтому, например, путь, предоставленный одному из методов пути, может содержать параметры матрицы или несколько сегментов пути, поскольку разделители являются допустимыми символами и не будут кодироваться. Значения, закодированные в процентах, также распознаются там, где это разрешено, и не будут кодироваться дважды.

person Community    schedule 14.01.2009
comment
URL недоступен. Но download.oracle.com/javaee/6 / api / javax / ws / rs / core / уже доступен - person sergtk; 24.12.2010
comment
@sergdev, исправил ссылку. Спасибо, что подняли голову! - person Gili; 19.01.2011
comment
Как именно вы получили ожидаемый результат, упомянутый выше, с помощью UriBuilder? Я понятия не имею, как сказать ему кодировать часть до?. Спасибо! - person tbk; 24.05.2011
comment
Если вы не используете JAX-RS и используете Spring, вы можете использовать Spring UriUtils - person Adam Gent; 16.07.2011
comment
@tbh, я хотел сказать, что если вы используете UriBuilder, он будет кодировать то, что нужно кодировать за вас. Если вы хотите вручную кодировать разделы текста, оказывается, что stackoverflow.com/questions/304806/ будет работать. В качестве альтернативы вы можете использовать UriBuilder.fromPath (host /). MatrixParam (key, google.com/resource?key=value1 & value2) .build (), и вы вернетесь host /. - person Gili; 07.11.2011
comment
Остерегайтесь использования UriBuilder для бесплатных URL-адресов, которые не используют схему параметров JAX-RS с фигурными скобками. Даже если это может быть экзотическое значение, попробуйте следующее: UriBuilder.fromPath("http://www.query.example/").queryParam("key", "{val}").build(); не удастся. "http://www.query.example?key=" + URLEncoder.encode("{val}", "UTF-8") будет работать. - person ujay68; 10.09.2015
comment
@ ujay68: UriBuilder рассматривает фигурные скобки как разделители шаблонов. Вы пробовали UriBuilder.fromPath("http://www.query.example/").queryParam("key", "{val}").build("{val}")? - person Julien Carsique; 29.10.2015
comment
К вашему сведению. Если у вас уже есть полная строка URL-адреса и вы просто заботитесь о том, чтобы специальные символы заменялись должным образом, вы можете просто создать ее следующим образом: UriBuilder.fromPath (urlString) .build (); Это закодирует все специальные символы справа от первого / в конце имени хоста URL-адреса. - person AdeelMufti; 09.05.2016

Вы также можете использовать Spring UriUtils

person Community    schedule 16.07.2011

У меня недостаточно репутации, чтобы комментировать ответы, но я просто хотел отметить, что загрузка JSR-311 api сама по себе не сработает. Вам необходимо загрузить эталонную реализацию (jersey).

Только загрузка api со страницы JSR даст вам исключение ClassNotFoundException, когда api попытается найти реализацию во время выполнения.

person Community    schedule 30.12.2009
comment
в частности, вам нужны jsr311-api, jersey-server и jersey-core jar. - person yincrash; 31.12.2009

Я написал свой, он короткий, очень простой, и вы можете скопировать его, если хотите: http://www.dmurph.com/2011/01/java-uri-encoder/

person Community    schedule 17.01.2011
comment
Думаю, людям не нравится это решение, потому что, возможно, они опасаются, что в нем будут ошибки и т. Д. Оно выглядит довольно всеобъемлющим, и в нем уже исправлена ​​пара ошибок, поэтому я думаю, что попробую его. И Java, и Objective C не имеют встроенных подпрограмм для такого кодирования, что просто ... сбивает с толку - person Herr Grumps; 10.10.2012
comment
Хм, это для самого URI, а не для параметров? - person Somatik; 11.12.2012
comment
Пробелы должны быть экранированы :) Он будет включать только цифры, буквы и символы 'mark' как неэкранированные - person Daniel Murphy; 08.05.2013
comment
@HerrGrumps Что? Obj-C уже давно имеет встроенную кодировку URL. - person Jadar; 31.01.2017
comment
@ Джадар а? хорошо, может быть, я ошибался в Obj-C и / или Java, не имея его - извините :) Для справки, возможно, вы можете опубликовать ответ с некоторыми именами классов / методов в том случае, если это может помочь кому-то, кто может не знать, куда посмотри (как я;)) - person Herr Grumps; 31.01.2017
comment
@HerrGrumps Не уверен насчет чистой Java, но в итоге я использовал классы, специфичные для Android. В iOS вы можете использовать класс URLComponents, чтобы разбить URL-адрес на составные части, и свойство queryItems для установки параметров. Но это выходит за рамки этого ответа и вопроса. ;) - person Jadar; 01.02.2017

Похоже, что CharEscapers из Google GData-java-client имеет то, что вы хотите. У него есть метод uriPathEscaper, uriQueryStringEscaper и общий uriEscaper. (Все возвращают объект Escaper, который действительно выполняет экранирование). Лицензия Apache.

person Community    schedule 14.01.2009
comment
К сожалению, он использует некоторые другие классы и интерфейсы, но я думаю, вы сможете изменить его в соответствии со своими потребностями. - person Peter Štibraný; 14.01.2009
comment
Должен быть способ попроще. Меня удивляет, что этот общий вариант использования (создание URI) сделать не так просто. java.net.URI должен работать лучше. - person Gili; 14.01.2009
comment
Я был удивлен, насколько запутана эта область (честно говоря, я даже не знал, что есть такая вещь, как специальная кодировка URI ... Я кое-что узнал). - person Peter Štibraný; 14.01.2009
comment
Питер, я только что понял, что это может сработать: jsr311.dev.java.net/nonav/releases/1.0/javax/ws/rs/core/ Я все равно использую JAX-RS для своего приложения. Я попробую и доложу. - person Gili; 14.01.2009
comment
Питер, добавьте следующее, и я отмечу его как принятый: javax.ws.rs.core.UriBuilder сделает то, что вы хотите: jsr311.dev.java.net/nonav/releases/1.0/javax/ws/rs/core/ - person Gili; 14.01.2009
comment
Не стесняйтесь отвечать на свой вопрос сами :-) Вы нашли решение, которое лучше всего подходит для вас. Люди, которые ищут ту же проблему, могут выбрать то, что им подходит. - person Peter Štibraný; 14.01.2009
comment
Причина, по которой я хочу, чтобы вы опубликовали ответ, заключается в том, что я не могу принять свой ответ. Отправьте новый ответ, и я его приму. - person Gili; 14.01.2009
comment
В ПОРЯДКЕ. Не знал о принятии собственного ответа, думал, что это возможно. - person Peter Štibraný; 14.01.2009
comment
+1 для CharEscapers. Сегодня я столкнулся с этой проблемой, и это исправлено: // false заставит пробелы кодироваться как% 20 CharEscapers.uriEscaper (false) .escape (value); - person James Cooper; 12.12.2009

Я думаю, что класс URI это тот, который вы ищете.

person Community    schedule 14.01.2009
comment
Это не помогает, потому что ожидает, что я передам полную строку запроса. У него нет возможности узнать, какая часть строки должна быть закодирована, а какая - нет. Мне нужен метод, который принимает необработанное значение параметра и передает закодированную форму URL. - person Gili; 14.01.2009
comment
да. Stackoverflow отмечает вопросы как отвеченные, если за них один раз проголосовали. За этот ответ проголосовал один человек, а я проголосовал против. Он по-прежнему отмечает мои вопросы как отвеченные в последний раз, когда я проверял. - person Gili; 14.01.2009
comment
Виноват. Ты прав. Я предположил, что одобренный ответ означает ... ну вы знаете, ответ с положительным числом слева ... - person A. Rex; 14.01.2009
comment
То же самое, пожалуйста, проголосуйте за stackoverflow.uservoice.com/pages/general/suggestions/ - person Gili; 14.01.2009
comment
Почему бы вам не обновить свой вопрос, чтобы указать, что класс URI вам не подходит? В противном случае кто-то другой войдет в тот же совет, даже если я удалю свой ответ. Кстати, почему нельзя закодировать полный URI? - person Glenn; 14.01.2009
comment
Я обновлю вопрос. Причина, по которой полный URI не может быть закодирован, заключается в том, что если я передаю ключ = значение с пробелами и все еще являюсь частью значения, конструктор не имеет возможности узнать, где значение начинается и заканчивается. - person Gili; 14.01.2009

Ммм, я знаю, что вы уже отказались от URLEncoder, но, несмотря на то, что говорят документы, я решил попробовать.

Вы сказали:

Например, при вводе:

http://google.com/resource?key=value

Ожидаю на выходе:

http% 3a% 2f% 2fgoogle.com% 2fresource% 3fkey% 3dvalue

So:

C:\oreyes\samples\java\URL>type URLEncodeSample.java
import java.net.*;

public class URLEncodeSample {
    public static void main( String [] args ) throws Throwable {
        System.out.println( URLEncoder.encode( args[0], "UTF-8" ));
    }
}

C:\oreyes\samples\java\URL>javac URLEncodeSample.java

C:\oreyes\samples\java\URL>java URLEncodeSample "http://google.com/resource?key=value"
http%3A%2F%2Fgoogle.com%2Fresource%3Fkey%3Dvalue

Как и ожидалось.

В чем будет проблема?

person OscarRyz    schedule 14.01.2009
comment
Он похож на RFC2396, но не то же самое. Например, попробуйте кодировать пробелы. URLEncoder закодирует его как '+', вместо этого URI ожидают% 20. Есть и другие отличия. - person Gili; 14.01.2009
comment
Хорошо, но вы не будете кодировать: значение с пробелом, а значение + с + пробелом, например: - person OscarRyz; 14.01.2009
comment
например: java URLEncodeSample google.com/resource?key=value+with+spaces http% 3A% 2F% 2Fgoogle.com% 2Fresource% 3Fkey% 3Dvalue% 2Bwith% 2Bspaces - person OscarRyz; 14.01.2009
comment
Существует целый ряд правил, которым нужно следовать для RFC 2369. Вместо того, чтобы играть в игры со входной строкой, я бы предпочел найти класс, который правильно кодирует вещи. - person Gili; 14.01.2009
comment
Что ты собираешься делать? Это было бы очень полезно знать, чтобы дать вам правильный ответ. - person OscarRyz; 14.01.2009