Вопрос по http, encoding, java – Java URL кодирование параметров строки запроса

614

Скажи, что у меня есть URL

http://example.com/query?q=

и у меня есть запрос, введенный пользователем, например:

случайное слово £ 500 банк $

Я хочу, чтобы результат был правильно закодированным URL:

http://example.com/query?q=random%20word%20%A3500%20bank%20%24

Как лучше всего этого добиться? Я пыталсяURLEncoder и создание объектов URI / URL, но ни один из них не получается совершенно правильным.

Почему ты ожидаешь, что $ будет кодироваться в процентах? jschnasse
Что ты имеешь в виду под словом "ни один из них не подходит"? Mark Elliot
Я использовал URI.create и заменил пробелы на + в строке запроса. На сайте клиента он преобразовал + обратно в пробелы, когда я выбрал строки запроса. Это сработало для меня. ND27

Ваш Ответ

9   ответов
6

роения и кодирования параметров запроса -

С использованием HttpComponents 4.x - URLEncodedUtils

Для использования HttpClient 3.x - EncodingUtil

1028

URLEncoder должен быть путь. Вам нужно только иметь в виду, чтобы закодироватьтольк имя и / или значение отдельного параметра строки запроса, а не весь URL, наверняка не символ-разделитель параметра строки запроса& ни символ разделитель имя-значение параметра=.

String url = "http://example.com/query?q=" + URLEncoder.encode(q, "UTF-8");

Обратите внимание, что пробелы в параметрах запроса представлены как+, не%20, который законно действителен.%20 обычно используется для представления пробелов в самом URI (часть перед символом-разделителем строк запроса URI ?), не в строке запроса (часть после?).

Также обратите внимание, что есть дваencode() методы. Один без аргумента charset, а другой с. Один без аргумента charset устарел. Никогда не используйте его и всегда указывайте аргумент charset. Javadoc даже явно рекомендует использовать кодировку UTF-8, как предписано RFC3986 а также W3C.

Все остальные символы небезопасны и сначала преобразуются в один или несколько байтов с использованием некоторой схемы кодирования. Затем каждый байт представлен трехсимвольной строкой «% xy», где xy - шестнадцатеричное представление байта из двух цифр. Рекомендуемая схема кодирования: UTF-8. Однако из соображений совместимости, если кодировка не указана, используется кодировка платформы по умолчанию.

Смотрите также Что каждый веб-разработчик должен знать о кодировке URL
ты должен использовать StandardCharsets.UTF_8 вместо жестко закодированной константы. TmTron
В URL может быть 2 типа параметров. Строка запроса (сопровождаемая?) И параметр пути (как правило, часть самого URL). Итак, что насчет параметров пути. URLEncoder производит + для пространства даже для параметров пути. Фактически он просто не обрабатывает ничего, кроме строки запроса. Кроме того, это поведение не синхронизировано с серверами узла js. Поэтому для меня этот класс - пустая трата времени, и его нельзя использовать иначе, как для очень специфических / специальных сценариев. sharadendu sinha
@ sharadendusinha: как задокументировано и дано ответ,URLEncoder соответствует параметрам запроса в кодировке URLapplication/x-www-form-urlencoded правила. Параметры пути не вписываются в эту категорию. Вместо этого вам нужен кодировщик URI. BalusC
Добавляя к комментарию @TmTron, точнее следует использовать строковую константуStandardCharsets.UTF_8.name() Jose Duarte
@ WijaySharma: потому что специфичные для URL символы также будут кодироваться. Это следует делать только в том случае, если вы хотите передать весь URL-адрес в качестве параметра запроса другого URL-адреса. BalusC
145

URLEncoder. Помимо неправильного имени URLEncoder не имеет ничего общего с URL-адресами), неэффективно (используетStringBuffer вместо Builder и делает несколько других вещей, которые медленны) Это также слишком легко облажаться.

Вместо этого я бы использовалURIBuilder или Spring'sorg.springframework.web.util.UriUtils.encodeQuery или Commons ApacheHttpClient. Причина в том, что вы должны экранировать имя параметров запроса (например, ответ BalusCq) иначе, чем значение параметра.

Единственный недостаток вышесказанного (что я узнал до боли) - это то, что URL не являются истинным подмножеством URI.

Образец кода

import org.apache.http.client.utils.URIBuilder;

URIBuilder ub = new URIBuilder("http://example.com/query");
ub.addParameter("q", "random word £500 bank \$");
String url = ub.toString();

// Result: http://example.com/query?q=random+word+%C2%A3500+bank+%24

Так как я просто ссылаюсь на другие ответы, я отметил это как вики сообщества. Не стесняйтесь редактировать.

Почему это никак не связано с URL-адресами? Luis Sep
@ Луис:URLEncoder, как говорит его javadoc, намеревался закодировать соответствие параметров строки запросаapplication/x-www-form-urlencoded как описано в спецификации HTML: W3.org / TR / html4 / взаимодействуют / .... Некоторые пользователи действительно путают / злоупотребляют им для кодирования целых URI, как, по-видимому, сделал нынешний ответчик. BalusC
@ LuisSep короче URLEncoder для кодирования для отправки формы. Это не для побега. Это не Точный то же самое экранирование, которое вы использовали бы для создания URL-адресов для размещения на вашей веб-странице, но оказалось, что оно достаточно похоже, чтобы люди злоупотребляли им. Единственный раз, когда вы должны использовать URLEncoder, это если вы пишете HTTP-клиент (и даже тогда есть гораздо лучшие варианты для кодирования). Adam Gent
@ BalusC " Некоторые пользователи действительно путают / злоупотребляют им для кодирования целых URI, как, по-видимому, сделал нынешний ответчик. ". Вы ошиблись. Я никогда не говорил, что я облажался с этим. Я только что видел других, которые сделали это, чьи ошибки я должен исправить. Часть, которую я облажал, состоит в том, что класс URL Java будет принимать неэкранированные скобки, но не класс URI. Есть много способов испортить создание URL, и не все такие блестящие, как вы. Я бы сказал, что большинство пользователей, которые ищут SOR для URLEncoding, вероятно, являются " пользователи действительно путают / злоупотребляют "URI сбежал. Adam Gent
Вопрос не об этом, но ваш ответ подразумевает это. BalusC
88

Сначала нужно создать URI, например:

    String urlStr = "http://www.example.com/CEREC® Materials & Accessories/IPS Empress® CAD.pdf"
    URL url= new URL(urlStr);
    URI uri = new URI(url.getProtocol(), url.getUserInfo(), url.getHost(), url.getPort(), url.getPath(), url.getQuery(), url.getRef());

Затем преобразуйте этот Uri в ASCII-строку:

    urlStr=uri.toASCIIString();

Теперь ваша строка URL полностью закодирована. Сначала мы сделали простое кодирование URL, а затем преобразовали ее в строку ASCII, чтобы убедиться, что в строке не осталось символов вне US-ASCII. Именно так и поступают браузеры.

Благодарность! Глупо, что ваше решение работает, но встроенноеURL.toURI() нет. user11153
К сожалению, это, похоже, не работает с "file: ///" (например: "file: /// some / directory / a, содержащий spaces.html"); бомба с MalformedURLException в "новом URL ()"; есть идеи как это исправить? ZioByte
Вам нужно сделать что-то вроде этого: String urlStr = " Некоторые / каталог / а файл, содержащий spaces.html "; URL url = новый URL (urlStr); URI uri = новый URI (url.getProtocol (), url.getUserInfo (), url.getHost (), url.getPort (), url.getPath (), url.getQuery (), url.getRef ()); urlStr = uri.toASCIIString (); urlStr.replace ("http: //", "file: ///"); я не проверял его, но я думаю это сработает ....:) M Abdul Sami
@ tibi вы можете просто использовать метод uri.toString () для преобразования его в строку вместо строки Ascii. M Abdul Sami
API, с которым я работал, не приняли+ замена пробелов, но принял% 20, так что это решение работало лучше, чем BalusC, спасибо! Julian Honma
32
Они страдают от тех же глупых правил ухода, что иURLEncoder. 2rs2ts
Не уверен, что у них есть проблема. они различают, например, "+" или "% 20" для выхода "" (образуют параметр или путь), которыйURLEncoder нет. Emmanuel Touzery
Это сработало для меня, я просто заменил вызов URLEncoder () для вызова UrlEscapers.urlFragmentEscaper (), и это сработало, не ясно, должен ли я вместо этого использовать UrlEscapers.urlPathSegmentEscaper (). Paul Taylor
На самом деле это не работает для меня, потому что, в отличие от URLEncoder, он не кодирует '+', он оставляет его в покое, сервер декодирует '+' как пробел, тогда как если я использую URLEncoder '+, они преобразуются в% 2B и корректно декодируются обратно в + Paul Taylor
Ссылка на обновление: UrlEscapers mgaert
5

который вы можете использовать в своем коде для преобразования строки URL-адреса и сопоставления параметров в допустимую кодированную строку URL-адреса, содержащую параметры запроса.

String addQueryStringToUrlString(String url, final Map<Object, Object> parameters) throws UnsupportedEncodingException {
    if (parameters == null) {
        return url;
    }

    for (Map.Entry<Object, Object> parameter : parameters.entrySet()) {

        final String encodedKey = URLEncoder.encode(parameter.getKey().toString(), "UTF-8");
        final String encodedValue = URLEncoder.encode(parameter.getValue().toString(), "UTF-8");

        if (!url.contains("?")) {
            url += "?" + encodedKey + "=" + encodedValue;
        } else {
            url += "&" + encodedKey + "=" + encodedValue;
        }
    }

    return url;
}
4

товых случаев, предоставленныхWeb Plattform Tes, ts):

0 Проверьте, если URL уже закодирован. Замените '+' кодированные пробелы на '% 20' кодированные пробелы.

1. Разделить URL на структурные части. Используйтеjava.net.URL для этого

2. Правильно закодируйте каждую структурную часть!

3. ИспользуйтеIDN.toASCII(putDomainNameHere) в Punycode закодировать имя хоста!

4 Используйтеjava.net.URI.toASCIIString()т @ до процентного кодирования, кодированного в NFC юникода - (лучше было бы NFKC!). Для получения дополнительной информации см .: Как правильно закодировать этот URL

URL url= new URL("http://example.com/query?q=random word £500 bank $");
URI uri = new URI(url.getProtocol(), url.getUserInfo(), IDN.toASCII(url.getHost()), url.getPort(), url.getPath(), url.getQuery(), url.getRef());
String correctEncodedURL=uri.toASCIIString(); 
System.out.println(correctEncodedURL);

Печать

http://example.com/query?q=random%20word%20%C2%A3500%20bank%20$

Вот несколько примеров, которые также будут работать правильно

{
      "in" : "http://نامه‌ای.com/",
     "out" : "http://xn--mgba3gch31f.com/"
},{
     "in" : "http://www.example.com/‥/foo",
     "out" : "http://www.example.com/%E2%80%A5/foo"
},{
     "in" : "http://search.barnesandnoble.com/booksearch/first book.pdf", 
     "out" : "http://search.barnesandnoble.com/booksearch/first%20book.pdf"
}, {
     "in" : "http://example.com/query?q=random word £500 bank $", 
     "out" : "http://example.com/query?q=random%20word%20%C2%A3500%20bank%20$"
}
0

В Android я бы использовал этот код:

Uri myUI = Uri.parse ("http://example.com/query").buildUpon().appendQueryParameter("q","random word A3500 bank 24").build();

ГдеUri этоandroid.net.Uri

Это не использует стандартный Java API. Поэтому, пожалуйста, укажите используемую библиотеку. rmuller
-2
Используйте это: URLEncoder.encode (query, StandardCharsets.UTF_8.displayName ()); или это: URLEncoder.encode (запрос, "UTF-8");

Вы можете использовать следующий код.

String encodedUrl1 = UriUtils.encodeQuery(query, "UTF-8");//not change 
String encodedUrl2 = URLEncoder.encode(query, "UTF-8");//changed
String encodedUrl3 = URLEncoder.encode(query, StandardCharsets.UTF_8.displayName());//changed

System.out.println("url1 " + encodedUrl1 + "\n" + "url2=" + encodedUrl2 + "\n" + "url3=" + encodedUrl3);
Не верно. Вы должны кодировать имена параметров и значения отдельно. Кодирование всей строки запроса также будет кодировать= а также& разделители, что не правильно. user207421

Похожие вопросы