Вопрос-ответ

HTTP URL Address Encoding in Java

Кодирование URL-адреса HTTP в Java

Мое автономное приложение Java получает URL-адрес (который указывает на файл) от пользователя, и мне нужно нажать на него и загрузить. Проблема, с которой я сталкиваюсь, заключается в том, что я не могу правильно закодировать URL-адрес HTTP...

Пример:

URL:  http://search.barnesandnoble.com/booksearch/first book.pdf

java.net.URLEncoder.encode(url.toString(), "ISO-8859-1");

возвращает мне:

http%3A%2F%2Fsearch.barnesandnoble.com%2Fbooksearch%2Ffirst+book.pdf

Но то, что я хочу, это

http://search.barnesandnoble.com/booksearch/first%20book.pdf

(пробел заменен на %20)

Я думаю, URLEncoder не предназначен для кодирования URL-адресов HTTP... В JavaDoc написано "Служебный класс для кодирования форм HTML"... Есть ли какой-либо другой способ сделать это?

Переведено автоматически
Ответ 1

Класс java.net.URI может помочь; в документации по URL вы найдете


Обратите внимание, класс URI действительно выполняет экранирование полей своего компонента при определенных обстоятельствах. Рекомендуемый способ управлять кодировкой и декодированием URL-адресов - использовать URI


Используйте один из конструкторов с более чем одним аргументом, например:

URI uri = new URI(
"http",
"search.barnesandnoble.com",
"/booksearch/first book.pdf",
null);
URL url = uri.toURL();
//or String request = uri.toString();

(конструктор URI с одним аргументом НЕ экранирует недопустимые символы)


Приведенный выше код экранирует только недопустимые символы - он НЕ экранирует символы, отличные от ASCII (см. Комментарий фатиха).
Метод toASCIIString может использоваться для получения строки, состоящей только из символов US-ASCII:

URI uri = new URI(
"http",
"search.barnesandnoble.com",
"/booksearch/é",
null);
String request = uri.toASCIIString();

Для URL-адреса с запросом типа http://www.google.com/ig/api?weather=São Paulo используйте версию конструктора с 5 параметрами:

URI uri = new URI(
"http",
"www.google.com",
"/ig/api",
"weather=São Paulo",
null);
String request = uri.toASCIIString();
Ответ 2

Пожалуйста, имейте в виду, что большинство приведенных выше ответов НЕВЕРНЫ.

Класс URLEncoder, несмотря на название, - это НЕ то, что здесь должно быть. Жаль, что Sun назвала этот класс так раздражающе. URLEncoder предназначено для передачи данных в виде параметров, а не для кодирования самого URL-адреса.

Другими словами, "http://search.barnesandnoble.com/booksearch/first book.pdf" это URL. Параметрами могут быть, например, "http://search.barnesandnoble.com/booksearch/first book.pdf?parameter1=this&param2=that". Параметры - это то, для чего вы бы использовали URLEncoder.

Следующие два примера подчеркивают различия между ними.

Ниже приведены неправильные параметры в соответствии со стандартом HTTP. Обратите внимание, что амперсанд (&) и плюс (+) закодированы неправильно.

uri = new URI("http", null, "www.google.com", 80, 
"/help/me/book name+me/", "MY CRZY QUERY! +&+ :)", null);

// URI: http://www.google.com:80/help/me/book%20name+me/?MY%20CRZY%20QUERY!%20+&+%20:)

Следующие действия приведут к получению правильных параметров при правильном кодировании запроса. Обратите внимание на пробелы, амперсанды и плюсы.

uri = new URI("http", null, "www.google.com", 80, "/help/me/book name+me/", URLEncoder.encode("MY CRZY QUERY! +&+ :)", "UTF-8"), null);

// URI: http://www.google.com:80/help/me/book%20name+me/?MY+CRZY+QUERY%2521+%252B%2526%252B+%253A%2529
Ответ 3

Я собираюсь добавить здесь одно предложение, предназначенное для пользователей Android. Вы можете сделать это, чтобы избежать необходимости получать какие-либо внешние библиотеки. Кроме того, все решения для поиска / замены символов, предложенные в некоторых ответах выше, опасны, и их следует избегать.

Попробуйте это:

String urlStr = "http://abc.dev.domain.com/0007AC/ads/800x480 15sec h.264.mp4";
URL url = new URL(urlStr);
URI uri = new URI(url.getProtocol(), url.getUserInfo(), url.getHost(), url.getPort(), url.getPath(), url.getQuery(), url.getRef());
url = uri.toURL();

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

Это использует преимущества пары функций, доступных вам в классах Android. Во-первых, класс URL может разбивать URL-адрес на соответствующие компоненты, поэтому вам не нужно выполнять какую-либо работу по поиску / замене строк. Во-вторых, этот подход использует преимущество функции класса URI для правильного экранирования компонентов, когда вы создаете URI через компоненты, а не из одной строки.

Прелесть этого подхода в том, что вы можете взять любую допустимую строку URL и заставить ее работать, не требуя от вас каких-либо специальных знаний о ней самостоятельно.

Ответ 4

решение, которое я разработал, гораздо более стабильное, чем любое другое:

public class URLParamEncoder {

public static String encode(String input) {
StringBuilder resultStr = new StringBuilder();
for (char ch : input.toCharArray()) {
if (isUnsafe(ch)) {
resultStr.append('%');
resultStr.append(toHex(ch / 16));
resultStr.append(toHex(ch % 16));
} else {
resultStr.append(ch);
}
}
return resultStr.toString();
}

private static char toHex(int ch) {
return (char) (ch < 10 ? '0' + ch : 'A' + ch - 10);
}

private static boolean isUnsafe(char ch) {
if (ch > 128 || ch < 0)
return true;
return " %$&+,/:;=?@<>#%".indexOf(ch) >= 0;
}

}
java