Кодировка URL-адреса Java: URLEncoder против URI

Глядя на веб-страницу кодирования URL-адресов W3 Schools, говорится, что @ должно быть закодировано как %40, а space должно быть кодируется как %20.

Я пробовал как URLEncoder, так и URI, но ни один из них не работает должным образом:

import java.net.URI;
import java.net.URLEncoder;

public class Test {
    public static void main(String[] args) throws Exception {

        // Prints me%40home.com (CORRECT)
        System.out.println(URLEncoder.encode("[email protected]", "UTF-8"));

        // Prints Email+Address (WRONG: Should be Email%20Address)
        System.out.println(URLEncoder.encode("Email Address", "UTF-8"));

        // http://www.home.com/test?Email%[email protected]
        // (WRONG: it has not encoded the @ in the email address)
        URI uri = new URI("http", "www.home.com", "/test", "Email [email protected]", null);
        System.out.println(uri.toString());
    }
}

По какой-то причине URLEncoder делает адрес электронной почты правильно, но не пробелы, а URI делает пробелы валютой, но не адреса электронной почты.

Как я должен кодировать эти 2 параметра, чтобы они соответствовали тому, что w3schools считает правильным (или w3schools ошибается?)


person John Farrelly    schedule 14.01.2013    source источник
comment
Если вы смотрите на w3schools.com, значит, вы делаете это неправильно. См. это   -  person Srinivas    schedule 14.01.2013
comment
@Srinivas веб-служба, которую я использую, явно игнорирует запросы, если только параметры не закодированы, как описано на веб-странице w3schools :(   -  person John Farrelly    schedule 14.01.2013
comment
URLEncoder кодирует не в соответствии со спецификацией URL, а в соответствии с форматом application/x-www-form-urlencoded MIME (это то, что большинство серверов приложений ожидает для ключей/значений параметров). Тип URI кодирует в соответствии с его документацией, то есть это не полный Конструктор URL. Обратите внимание, что разные части URI имеют разные правила. См. эту публикацию. больше анализа.   -  person McDowell    schedule 14.01.2013
comment
@McDowell Да, я думаю, мне следовало спросить, как мне заставить java делать то, что делает encodeURIComponent() в JavaScript. Я проверю вашу библиотеку.   -  person John Farrelly    schedule 14.01.2013


Ответы (2)


Хотя я думаю, что ответ от @fge является правильным, поскольку я использовал сторонний веб-сервис, который полагался на кодировку, описанную в статье W3Schools, я следовал ответу из Java-эквивалент encodeURIComponent в JavaScript, который производит идентичный вывод?

public static String encodeURIComponent(String s) {
    String result;

    try {
        result = URLEncoder.encode(s, "UTF-8")
                .replaceAll("\\+", "%20")
                .replaceAll("\\%21", "!")
                .replaceAll("\\%27", "'")
                .replaceAll("\\%28", "(")
                .replaceAll("\\%29", ")")
                .replaceAll("\\%7E", "~");
    } catch (UnsupportedEncodingException e) {
        result = s;
    }

    return result;
}
person John Farrelly    schedule 20.01.2013
comment
Вы забыли символ &, который важен для декодирования URL-адреса (либо для метода GET, либо для метода POST), потому что это символ, который разделяет ключи в запросе. - person Giorgos Fandomas; 10.08.2015
comment
Я вынужден указать, что w3schools — это не W3C. Они совсем, совсем разные. - person Mike B; 06.11.2018

Синтаксис URI определяется RFC 3986 (допустимое содержимое строки запроса определяется в разделе 3.4). URI Java соответствует этому RFC с несколькими предостережениями, упомянутыми в его Javadoc.

Вы заметите, что правило грамматики pchar определяется следующим образом:

pchar = незарезервировано / pct-кодирование / субразделители / ":" / "@"

Это означает, что @ является законным в строке запроса.

Доверяйте URI. Он будет делать правильные "законные" действия.

Наконец, если вы посмотрите на Javadoc URLEncoder, вы видите, что он гласит:

Этот класс содержит статические методы для преобразования строки в формат MIME application/x-www-form-urlencoded.

Это не то же самое, что строка запроса, определенная спецификацией URI.

person fge    schedule 14.01.2013
comment
Я думаю, что вопрос, который я должен был задать, заключается в том, как заставить java кодировать URL-адрес так же, как JavaScript encodeURIComponent, поскольку это то, что ожидает принимающий веб-сервис: stackoverflow.com/questions/607176/ - person John Farrelly; 14.01.2013
comment
С тех пор я разработал библиотеку, которая делает шаблоны URI (RFC 6570), что еще более мощно;) - person fge; 05.07.2013
comment
это странно... Javadocs для URI утверждает, что он следует RFC 2396, даже в Java 8, где RFC 2396 относится к 1998 году, и он был устарел в соответствии с RFC 3986 с 2005 года. - person arcuri82; 28.03.2017