Перевірка URL-адреси на Java


103

Мені хотілося знати, чи є в Java якісь стандартні API для перевірки заданої URL-адреси? Я хочу перевірити, чи правильно вказано рядок URL-адреси, тобто даний протокол є дійсним, а потім перевірити, чи можна встановити з'єднання.

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

Це може бути через налаштування проксі-сервера? Я спробував встановити властивості системи для проксі, але успіху не було.

Дайте мені знати, що я роблю неправильно.


2
Тут, здається, є 2 питання; Перевірка URL-адреси та пошук причини ConnectException
Бен Джеймс

Оскільки це перший хіт Google для java url validator, тут справді виникають питання, як перевірити URL (з огляду на рядок) та як перевірити, чи доступний URL (наприклад, через http-з'єднання).
vikingsteve

Відповіді:


157

На користь спільноти, оскільки ця тема є найпопулярнішою в 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");
}

37
Цей клас URLValidator позначений застарілим. Рекомендований URLValidator міститься в пакеті процедур: commons.apache.org/validator/apidocs/org/apache/commons/…
Spektr

6
@Spektr Я поправив посилання. Дякую.
Йонатан

18
Я не бачу, як це стандартний API
b1nary.atr0phy

2
У UrlValidator є власний набір відомих проблем. Чи є альтернативна бібліотека, яка підтримується активніше?
Алекс Авербух

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-адресу для а new HttpGet(url), ви можете вловлювати IllegalArgumentException HttpGet(...)кидки, якщо є неправильна URL-адреса. І HttpResponseбуде кидати речі і на вас, якщо є проблеми з отриманням даних.
Peter Ajtai

2
Підключення підтверджує лише доступність хоста. Не має нічого спільного з дійсністю URL-адреси.
Андрій Родіонов

2
MalformedURLException не є безпечною стратегією для перевірки дійсної форми URL-адреси. Ця відповідь вводить в оману.
Мартін

1
@Martin: чи можете ви пояснити, чому це не безпечно?
Джероен Ванневель

28
Це дуже і дуже дорого. openConnection / connect насправді спробує підключитися до ресурсу http. Це, мабуть, є одним із найдорожчих способів підтвердження URL-адреси, який я коли-небудь бачив.
Гленн Бех

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-адрес. Однак, цей метод вловлює лише один із найпростіших випадків, описаних вище.

Висновок полягає в тому, що не існує стандартного аналізатора URL-адрес Java для перевірки 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
Зауважте, що ця строкова-> 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.