URI - getHost возвращает null. Зачем?

Почему первый возвращает null, а второй возвращает mail.yahoo.com?

Разве это не странно? Если нет, то какая логика этого поведения?

Является ли подчеркивание виновником? Зачем?

public static void main(String[] args) throws Exception {
    java.net.URI uri = new java.net.URI("http://broken_arrow.huntingtonhelps.com");
    String host = uri.getHost();
    System.out.println("Host = [" + host + "].");

    uri = new java.net.URI("http://mail.yahoo.com");
    host = uri.getHost();
    System.out.println("Host = [" + host + "].");
}

Ответ 1

Как уже упоминалось в комментариях @hsz, это известная ошибка.

Но, давайте отладим и заглянем внутрь источников класса URI. Проблема внутри метода:

private int parseHostname(int start, int n):

анализ первого URI завершается неудачно в строках, if ((p < n) && !at(p, n, ':')) fail("Illegal character in hostname", p);

это связано с тем, что символ _ не предусмотрен внутри блока сканирования, он допускает только буквы, цифры и символы - (L_ALPHANUM, H_ALPHANUM, L_DASH и H_DASH).

И да, это еще не исправлено в Java 7.

Ответ 2

Это из-за подчеркивания в базовом uri. Просто снимите знак подчеркивания, чтобы проверить его. Он работает.

Как указано ниже:

public static void main(String[] args) throws Exception {
java.net.URI uri = new java.net.URI("http://brokenarrow.huntingtonhelps.com");
String host = uri.getHost();
System.out.println("Host = [" + host + "].");

uri = new java.net.URI("http://mail.yahoo.com");
host = uri.getHost();
System.out.println("Host = [" + host + "].");

}

Ответ 3

Я не думаю, что это ошибка в Java, я думаю, что Java правильно обрабатывает имена хостов в соответствии со спецификацией, есть хорошие объяснения спецификации здесь: http://en.wikipedia.org/wiki/Hostname#Restrictions_on_valid_host_names и здесь: http://www.netregister.biz/faqit.htm#1

В частности, имена хостов НЕ ДОЛЖНЫ содержать символы подчеркивания.

Ответ 4

Как уже упоминалось, это известная ошибка JVM. Хотя, если вы хотите выполнить HTTP-запрос на такой хост, вы все равно можете попытаться использовать обходной путь. Основная идея состоит в том, чтобы построить запрос, основанный на IP, а не на "неправильном" имени хоста. Но в этом случае вам также нужно добавить заголовок "Host" в запрос с правильным (оригинальным) именем хоста.

1: Вырезать имя хоста из URL (это пример, вы можете использовать более умный способ):

int n = url.indexOf("://");  
if (n > 0) { n += 3; } else { n = 0; }  
int m = url.indexOf(":", n);
int k = url.indexOf("/", n);  
if (-1 == m) { m = k; }  
String hostHeader;  
if (k > -1) {  
  hostHeader = url.substring(n, k);  
} else {  
  hostHeader = url.substring(n);  
}
String hostname;  
if (m > -1) {  
  hostname = url.substring(n, m);  
} else {  
  hostname = url.substring(n);  
}  

2: Получить имя хоста IP:

String IP = InetAddress.getByName(hostname).getHostAddress();

3: Создайте новый URL-адрес на основе IP:

String newURL = url.substring(0, n) + IP + url.substring(m);

4: Теперь используйте HTTP-библиотеку для подготовки запроса на новый URL (псевдокод):

HttpRequest req = ApacheHTTP.get(newUrl);

5: Теперь вы должны добавить заголовок "Host" с правильным (оригинальным) именем хоста:

req.addHeader("Host", hostHeader);

6: Теперь вы можете выполнить запрос (псевдокод):

String resp = req.getResponse().asString();

Ответ 5

Попробуйте использовать: new java.net.URL("http://broken_arrow.huntingtonhelps.com").getHost(). Имеет альтернативную реализацию парсинга. Если у вас есть экземпляр URI myUri, вызовите myUri.toURL().getHost().

Я столкнулся с этой проблемой URI в OpenJDK 1.8, и он отлично работал с URL.