Проверка URL-адреса в Java


104

Я хотел знать, есть ли в Java стандартные API-интерфейсы для проверки данного URL-адреса? Я хочу проверить оба, правильна ли строка URL-адреса, то есть данный протокол действителен, а затем проверить, можно ли установить соединение.

Я попытался использовать HttpURLConnection, указав URL-адрес и подключившись к нему. Кажется, что первая часть моего требования выполнена, но когда я пытаюсь выполнить HttpURLConnection.connect (), выдается исключение java.net.ConnectException: соединение отклонено.

Может это из-за настроек прокси? Я попытался установить свойства системы для прокси, но безуспешно.

Сообщите мне, что я делаю не так.


2
Кажется, здесь есть 2 вопроса; Проверка URL-адреса и поиск причины исключения ConnectException
Бен Джеймс,

Поскольку это первое обращение к Google java url validator, здесь действительно есть вопросы, как проверить URL-адрес (глядя на строку) и как проверить, доступен ли URL-адрес (например, через HTTP-соединение).
vikingsteve

Ответы:


158

На благо сообщества, так как эта ветка занимает первое место в Google при поиске
" url validator java "


Выявление исключений стоит дорого, и по возможности его следует избегать. Если вы просто хотите убедиться, что ваша строка является допустимым URL-адресом, вы можете использовать класс UrlValidator из проекта Apache Commons Validator .

Например:

String[] schemes = {"http","https"}; // DEFAULT schemes = "http", "https", "ftp"
UrlValidator urlValidator = new UrlValidator(schemes);
if (urlValidator.isValid("ftp://foo.bar.com/")) {
   System.out.println("URL is valid");
} else {
   System.out.println("URL is invalid");
}

38
Этот класс URLValidator помечен как устаревший. Рекомендуемая URLValidator в пакете подпрограмм: commons.apache.org/validator/apidocs/org/apache/commons/...
Спектр

6
@Spektr Я исправил ссылку. Спасибо.
Yonatan

18
Я не понимаю, насколько это стандартный API
b1nary.atr0phy

2
UrlValidator имеет собственный набор известных проблем. Есть ли альтернативная библиотека, которая поддерживается более активно?
Alex Averbuch

9
@AlexAverbuch: не могли бы вы рассказать о проблемах с UrlValidator? Не очень полезно просто сказать, что они существуют, но не сказать, что они из себя представляют.
cdmckay

33

Вам нужно создать как URLобъект, так и URLConnectionобъект. Следующий код проверяет как формат URL-адреса, так и возможность установления соединения:

try {
    URL url = new URL("http://www.yoursite.com/");
    URLConnection conn = url.openConnection();
    conn.connect();
} catch (MalformedURLException e) {
    // the URL is not in a valid form
} catch (IOException e) {
    // the connection couldn't be established
}

Обратите внимание, что есть несколько способов проверки неправильных URL-адресов / проблем. Например, если вы будете использовать свой URL-адрес для a new HttpGet(url), вы можете поймать IllegalArgumentException HttpGet(...)выбросы, если есть искаженный URL-адрес. И HttpResponseесли возникнут проблемы с получением данных, они тоже будут кидаться в вас.
Peter Ajtai

2
Соединение подтверждает только доступность хоста. Не имеет ничего общего с действительностью URL.
Андрей Родионов

2
MalformedURLException - небезопасная стратегия для проверки действительной формы URL-адреса. Этот ответ вводит в заблуждение.
Мартин

1
@ Мартин: не могли бы вы объяснить, почему это небезопасно?
Jeroen Vannevel

28
Это очень и очень дорого. openConnection / connect фактически попытается подключиться к http-ресурсу. Это должен быть один из самых дорогих способов, которые я когда-либо видел для проверки URL.
Glenn Bech

33

На java.net.URLсамом деле этот класс - не лучший способ проверки URL-адресов. MalformedURLExceptionэто не выброшен на все уродливую URL , во время строительства. Ловля IOExceptionна java.net.URL#openConnection().connect()не проверяет URL либо, только сказать кастрированный баран или не может быть установлено соединение.

Рассмотрим этот фрагмент кода:

    try {
        new URL("http://.com");
        new URL("http://com.");
        new URL("http:// ");
        new URL("ftp://::::@example.com");
    } catch (MalformedURLException malformedURLException) {
        malformedURLException.printStackTrace();
    }

..который не вызывает никаких исключений.

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

Примечание. Было высказано предположение, что URL#toURI()в сочетании с обработкой исключения java.net. URISyntaxExceptionможет облегчить проверку URL-адресов. Однако этот метод ловит только один из очень простых случаев, описанных выше.

Вывод состоит в том, что не существует стандартного парсера java URL для проверки URL.


Вы нашли решение этой проблемы ??
kidd0

@ bi0s.kidd0 Есть несколько библиотек, которые можно использовать, но мы решили накатить собственную. Он не полный, но может анализировать то, что нас интересует, включая URL-адреса, содержащие домены или IP-адреса (как v4, так и v6). github.com/jajja/arachne
Мартин

15

Используя только стандартный API, передайте строку URLобъекту, а затем преобразуйте ее в URIобъект. Это позволит точно определить действительность URL-адреса в соответствии со стандартом RFC2396.

Пример:

public boolean isValidURL(String url) {

    try {
        new URL(url).toURI();
    } catch (MalformedURLException | URISyntaxException e) {
        return false;
    }

    return true;
}

5
Обратите внимание, что эта схема проверки string-> url-> uri сообщает, что эти тестовые примеры действительны: "http: //.com" " com ." "ftp: // :::: @ example.com" "http: /test.com" "http: test.com" "http: /:" Таким образом, хотя это стандартный API, применяемые им правила проверки могут не соответствовать чего можно ожидать.
DaveK

10

Используйте android.webkit.URLUtilна android:

URLUtil.isValidUrl(URL_STRING);

Примечание. Это просто проверка исходной схемы URL-адреса, а не проверки правильности всего URL-адреса.


2
Только если вы, конечно, работаете над приложением для Android.
miva2

8

Есть способ выполнить проверку URL-адреса в строгом соответствии со стандартами Java, не прибегая к сторонним библиотекам:

boolean isValidURL(String url) {
  try {
    new URI(url).parseServerAuthority();
    return true;
  } catch (URISyntaxException e) {
    return false;
  }
}

Конструктор URIпроверок urlявляется допустимым URI, а вызов parseServerAuthorityгарантирует, что это URL (абсолютный или относительный), а не URN.


Выдается исключение: «Если компонент полномочий этого URI определен, но не может быть проанализирован как серверный орган в соответствии с RFC 2396». Хотя это намного лучше, чем большинство других предложений, он не может проверить URL.
Мартин

@Martin, Вы забыли про валидацию в конструкторе. Как я уже писал, комбинация URIвызова конструктора и parseServerAuthorityвызова проверяет URL, а не parseServerAuthorityтолько.
определено

1
На этой странице вы можете найти примеры, которые неверно подтверждены вашим предложением. Обратитесь к документации, и если она не предназначена для использования по назначению, не поощряйте ее использование.
Мартин

@Martin, можно конкретнее? Какие примеры, по вашему мнению, неверно подтверждены этим методом?
объявлено

1
@ Асу, да. Второй ://идет после хоста, :вводит номер порта, который может быть пустым в соответствии с синтаксисом. //это часть пути с пустым сегментом, что тоже верно. Если вы введете этот адрес в свой браузер, он попытается его открыть (но, скорее всего, не найдет названный сервер https;)).
объявлено

2

Просто важно отметить, что объект URL обрабатывает как проверку, так и соединение. Тогда разрешены только протоколы, для которых обработчик предоставлен в sun.net.www.protocol ( файл , ftp , gopher , http , https , jar , mailto , netdoc ). Например, попробуйте создать новый URL с протоколом ldap :

new URL("ldap://myhost:389")

Вы получите java.net.MalformedURLException: unknown protocol: ldap.

Вам необходимо реализовать собственный обработчик и зарегистрировать его через URL.setURLStreamHandlerFactory(). Довольно излишне, если вы просто хотите проверить синтаксис URL, регулярное выражение кажется более простым решением.


1

Вы уверены, что используете правильный прокси в качестве системных свойств?

Также, если вы используете 1.5 или 1.6, вы можете передать экземпляр java.net.Proxy методу openConnection (). Это более элегантно, imo:

//Proxy instance, proxy ip = 10.0.0.1 with port 8080
Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("10.0.0.1", 8080));
conn = new URL(urlString).openConnection(proxy);

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

0

Думаю, лучший ответ - от пользователя @ b1nary.atr0phy. Как-то я рекомендую объединить метод из ответа b1nay.atr0phy с регулярным выражением, чтобы охватить все возможные случаи.

public static final URL validateURL(String url, Logger logger) {

        URL u = null;
        try {  
            Pattern regex = Pattern.compile("(?i)^(?:(?:https?|ftp)://)(?:\\S+(?::\\S*)?@)?(?:(?!(?:10|127)(?:\\.\\d{1,3}){3})(?!(?:169\\.254|192\\.168)(?:\\.\\d{1,3}){2})(?!172\\.(?:1[6-9]|2\\d|3[0-1])(?:\\.\\d{1,3}){2})(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}(?:\\.(?:[1-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))|(?:(?:[a-z\\u00a1-\\uffff0-9]-*)*[a-z\\u00a1-\\uffff0-9]+)(?:\\.(?:[a-z\\u00a1-\\uffff0-9]-*)*[a-z\\u00a1-\\uffff0-9]+)*(?:\\.(?:[a-z\\u00a1-\\uffff]{2,}))\\.?)(?::\\d{2,5})?(?:[/?#]\\S*)?$");
            Matcher matcher = regex.matcher(url);
            if(!matcher.find()) {
                throw new URISyntaxException(url, "La url no está formada correctamente.");
            }
            u = new URL(url);  
            u.toURI(); 
        } catch (MalformedURLException e) {  
            logger.error("La url no está formada correctamente.");
        } catch (URISyntaxException e) {  
            logger.error("La url no está formada correctamente.");  
        }  

        return u;  

    }

1
С этим регулярным выражением есть несколько проблем: 1. URL-адреса без префикса недействительны (например, "stackoverflow.com"), это также включает URL-адреса с двумя суффиксами, если они не имеют префикса (например, "amazon.co.uk "). 2. IP-адреса всегда недействительны (например, « 127.0.0.1» ), независимо от того, используют они префикс или нет. Я бы предложил использовать "((http|https|ftp)://)?((\\w)*|([0-9]*)|([-|_])*)+([\\.|/]((\\w)*|([0-9]*)|([-|_])*))+"( источник ). Единственным недостатком этого регулярного выражения является то, что допустимы, например, «127.0..0.1» и «127.0».
Неф,

-2

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

//Proxy instance, proxy ip = 10.0.0.1 with port 8080
Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("10.0.0.1", 8080));
conn = new URL(urlString).openConnection(proxy);

Однако системные свойства не работают, как я упоминал ранее.

Еще раз спасибо.

С уважением, Кея

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.