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");
- Используйте это: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);