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

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

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

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

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

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

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

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

9 ответов

Решение

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

String q = "random word £500 bank $";
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. Однако из соображений совместимости, если кодировка не указана, используется кодировка платформы по умолчанию.

Смотрите также:

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

Вместо этого я бы использовал URIBuilder или весна org.springframework.web.util.UriUtils.encodeQuery или общий Apache HttpClient, Причина в том, что вы должны экранировать имя параметров запроса (т.е. ответ BalusC q) иначе, чем значение параметра.

Единственный недостаток вышеизложенного (который я обнаружил до боли) - это то, что 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

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

Вам нужно сначала создать 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. Именно так и поступают браузеры.

Используйте следующее стандартное решение Java (проходит около 100 тестовых случаев, предоставляемых Web Plattform Tests):

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$"
}

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

UriComponentsBuilder
        .fromUriString(url)
        .build()
        .encode()
        .toUri()

Библиотека Apache Http Components предоставляет удобную опцию для построения и кодирования параметров запроса -

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

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

Вот метод, который вы можете использовать в своем коде для преобразования строки 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;
}

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

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

куда Uri это android.net.Uri

В моем случае мне просто нужно было передать весь URL и закодировать только значение каждого параметра. Я не нашел общий код для этого (!!), поэтому я создал этот небольшой метод, чтобы сделать работу:

public static String encodeUrl(String url) throws Exception {
    if (url == null || !url.contains("?")) {
        return url;
    }

    List<String> list = new ArrayList<>();
    String rootUrl = url.split("\\?")[0] + "?";
    String paramsUrl = url.replace(rootUrl, "");
    List<String> paramsUrlList = Arrays.asList(paramsUrl.split("&"));
    for (String param : paramsUrlList) {
        if (param.contains("=")) {
            String key = param.split("=")[0];
            String value = param.replace(key + "=", "");
            list.add(key + "=" +  URLEncoder.encode(value, "UTF-8"));
        }
        else {
            list.add(param);
        }
    }

    return rootUrl + StringUtils.join(list, "&");
}

public static String decodeUrl(String url) throws Exception {
    return URLDecoder.decode(url, "UTF-8");
}

Он использует org.apache.commons.lang3.StringUtils

Я нашла простое решение твоего вопроса. Я тоже хотел использовать закодированный URL, но мне ничего не помогло.

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

использовать String example = "случайное слово 500 фунтов стерлингов банк $"; вы можете под кодом.

String example = "random word £500 bank $";
String URL = "http://example.com/query?q=" + example.replaceAll(" ","%20");
  1. Используйте это:URLEncoder.encode(query, StandardCharsets.UTF_8.displayName()); или это: URLEncoder.encode (запрос, "UTF-8");
  2. Вы можете использовать следующий код.

    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);
    
Другие вопросы по тегам