Validation de l'URL en Java

103

Je voulais savoir s'il existe des API standard en Java pour valider une URL donnée? Je veux vérifier à la fois si la chaîne d'URL est correcte, c'est-à-dire que le protocole donné est valide, puis pour vérifier si une connexion peut être établie.

J'ai essayé d'utiliser HttpURLConnection, en fournissant l'URL et en me connectant. La première partie de mon exigence semble être remplie mais lorsque j'essaie d'exécuter HttpURLConnection.connect (), une exception «java.net.ConnectException: Connection refusée» est levée.

Cela peut-il être dû aux paramètres de proxy? J'ai essayé de définir les propriétés système du proxy mais sans succès.

Faites-moi savoir ce que je fais de mal.

Keya
la source
2
Il semble y avoir 2 questions ici; Validation d'URL et recherche de la cause d'une exception ConnectException
Ben James
Puisqu'il s'agit du premier hit google pour java url validator, il y a en effet des questions ici, comment valider l'url (en regardant la chaîne) et comment vérifier si l'url est accessible (via une connexion http, par exemple).
vikingsteve

Réponses:

158

Pour le bénéfice de la communauté, puisque ce fil est en tête sur Google lors de la recherche de
" url validator java "


Attraper des exceptions est coûteux et doit être évité lorsque cela est possible. Si vous souhaitez simplement vérifier que votre chaîne est une URL valide, vous pouvez utiliser la classe UrlValidator du projet Apache Commons Validator .

Par exemple:

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");
}
Yonatan
la source
38
Cette classe URLValidator est marquée comme obsolète. L'URLValidator recommandé se trouve dans le package des routines: commons.apache.org/validator/apidocs/org/apache/commons/…
Spektr
6
@Spektr J'ai corrigé le lien. Merci.
Yonatan
18
Je ne vois pas en quoi il s'agit d' une API standard
b1nary.atr0phy
2
UrlValidator a son propre ensemble de problèmes connus. Existe-t-il une bibliothèque alternative qui est maintenue plus activement?
Alex Averbuch
9
@AlexAverbuch: pouvez-vous s'il vous plaît décrire quels sont les problèmes avec UrlValidator? Il n'est pas très utile de simplement dire qu'ils existent mais de ne pas dire ce qu'ils sont.
cdmckay
33

Vous devez créer à la fois un URLobjet et un URLConnectionobjet. Le code suivant testera à la fois le format de l'URL et si une connexion peut être établie:

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
}
Olly
la source
Notez qu'il existe plusieurs façons de vérifier les URL / problèmes mal formés. Par exemple, si vous utilisez votre URL pour a new HttpGet(url), vous pouvez attraper les IllegalArgumentException HttpGet(...)lancers s'il y a une URL mal formée. Et vous HttpResponselancera également des trucs s'il y a un problème avec l'obtention des données.
Peter Ajtai
2
La connexion valide uniquement la disponibilité de l'hôte. N'a rien à voir avec la validité de l'URL.
Andrey Rodionov
2
MalformedURLException n'est pas une stratégie sûre pour tester la forme valide d'une URL. Cette réponse est trompeuse.
Martin
1
@Martin: pouvez-vous expliquer pourquoi ce n'est pas sûr?
Jeroen Vannevel
28
C'est très, très cher. openConnection / connect essaiera en fait de se connecter à la ressource http. Cela doit être l'un des moyens les plus coûteux que j'aie jamais vu pour vérifier une URL.
Glenn Bech
33

La java.net.URLclasse n'est en fait pas du tout un bon moyen de valider les URL. MalformedURLExceptionn'est pas lancée sur toutes les URL mal formées pendant la construction. Attraper IOExceptionsur java.net.URL#openConnection().connect()ne valide pas l' URL soit, dire que si oui ou non la connexion peut être établie.

Considérez ce morceau de code:

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

..qui ne jette aucune exception.

Je recommande d'utiliser une API de validation implémentée à l'aide d'une grammaire sans contexte, ou dans une validation très simplifiée, utilisez simplement des expressions régulières. Cependant, j'ai besoin de quelqu'un pour suggérer une API supérieure ou standard pour cela, je n'ai commencé que récemment à la rechercher moi-même.

Remarque Il a été suggéré qu'en URL#toURI()combinaison avec la gestion de l'exception java.net. URISyntaxExceptionpeut faciliter la validation des URL. Cependant, cette méthode n'attrape qu'un des cas très simples ci-dessus.

La conclusion est qu'il n'y a pas d'analyseur d'URL Java standard pour valider les URL.

Martin
la source
Avez-vous trouvé une solution à ce problème?
kidd0
@ bi0s.kidd0 Plusieurs bibliothèques peuvent être utilisées, mais nous avons décidé de créer la nôtre. Ce n'est pas complet, mais peut analyser ce qui nous intéresse, y compris les URL contenant des domaines ou des adresses IP (v4 et v6). github.com/jajja/arachne
Martin
15

En utilisant uniquement l'API standard, passez la chaîne à un URLobjet puis convertissez-la en URIobjet. Cela déterminera avec précision la validité de l'URL selon la norme RFC2396.

Exemple:

public boolean isValidURL(String url) {

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

    return true;
}
b1nary.atr0phy
la source
5
Notez que ce schéma de validation string-> url-> uri signale que ces cas de test sont valides: "http: //.com" " com ." "ftp: // :::: @ example.com" "http: /test.com" "http: test.com" "http: /:" Ainsi, bien qu'il s'agisse d'une API standard, les règles de validation qu'elle applique peuvent ne pas être ce que l'on attend.
DaveK
10

Utilisez le android.webkit.URLUtilsur Android:

URLUtil.isValidUrl(URL_STRING);

Remarque: il s'agit simplement de vérifier le schéma initial de l'URL, et non pas que l'URL entière soit valide.

penduDev
la source
2
Uniquement si vous travaillez bien sur une application Android.
miva2
8

Il existe un moyen d'effectuer la validation d'URL dans le strict respect des normes Java sans recourir à des bibliothèques tierces:

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

Le constructeur de URIvérifications qui urlest un URI valide, et l'appel à parseServerAuthoritygarantit qu'il s'agit d'une URL (absolue ou relative) et non d'un URN.

dened
la source
L'exception est levée "Si le composant d'autorité de cet URI est défini mais ne peut pas être analysé comme une autorité basée sur le serveur conformément à la RFC 2396". Bien que ce soit bien meilleur que la plupart des autres propositions, il ne peut pas valider une URL.
Martin
@Martin, vous avez oublié la validation dans le constructeur. Comme je l'ai écrit, la combinaison de l' URIappel du constructeur et de l' parseServerAuthorityappel valide l'URL, pas parseServerAuthorityseule.
dened le
1
Vous pouvez trouver sur cette page des exemples qui ne sont pas correctement validés par votre suggestion. Reportez-vous à la documentation, et si elle n'est pas conçue pour votre utilisation prévue, veuillez ne pas en faire la promotion pour l'exploiter.
Martin
@Martin, pouvez-vous être plus précis? Quels exemples à votre avis sont incorrectement validés par cette méthode?
décédé
1
@Asu oui. Le second ://vient après l'hôte, :introduit le numéro de port, qui peut être vide selon la syntaxe. //est une partie du chemin avec un segment vide, qui est également valide. Si vous entrez cette adresse dans votre navigateur, il essaiera de l'ouvrir (mais ne trouvera probablement pas le serveur nommé https;)).
décédé
2

Il est simplement important de souligner que l'objet URL gère à la fois la validation et la connexion. Ensuite, seuls les protocoles pour lesquels un gestionnaire a été fourni dans sun.net.www.protocol sont autorisés ( file , ftp , gopher , http , https , jar , mailto , netdoc ) sont valides. Par exemple, essayez de créer une nouvelle URL avec le protocole ldap :

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

Vous obtiendrez un fichier java.net.MalformedURLException: unknown protocol: ldap.

Vous devez implémenter votre propre gestionnaire et l'enregistrer via URL.setURLStreamHandlerFactory(). Tout à fait exagéré si vous souhaitez simplement valider la syntaxe de l'URL, une expression régulière semble être une solution plus simple.

Doc Davluz
la source
1

Êtes-vous sûr d'utiliser le bon proxy comme propriétés système?

De plus, si vous utilisez 1.5 ou 1.6, vous pouvez passer une instance java.net.Proxy à la méthode openConnection (). C'est imo plus élégant:

//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);
NickDK
la source
Pourquoi serait-ce élégant ou même correct? Il utilise des ressources coûteuses lorsqu'il fonctionne, et il ne fonctionne pas pour une URL correcte n'est pas disponible pour la connexion lors du test.
Martin le
0

Je pense que la meilleure réponse vient de l'utilisateur @ b1nary.atr0phy. D'une manière ou d'une autre, je recommande de combiner la méthode de la réponse b1nay.atr0phy avec un regex pour couvrir tous les cas possibles.

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;  

    }
Genaut
la source
1
Il y a quelques problèmes avec cette expression régulière: 1. Les URL sans préfixe ne sont pas valides, (par exemple "stackoverflow.com"), cela inclut également les URL avec deux suffixes s'il leur manque le préfixe (par exemple "amazon.co.uk" "). 2. Les adresses IP sont toujours invalides (par exemple " 127.0.0.1" ), qu'elles utilisent le préfixe ou non. Je suggérerais d'utiliser "((http|https|ftp)://)?((\\w)*|([0-9]*)|([-|_])*)+([\\.|/]((\\w)*|([0-9]*)|([-|_])*))+"( source ). Le seul inconvénient de cette expression régulière est que, par exemple, "127.0..0.1" et "127.0" sont valides.
Néph
-2

Merci. Ouvrir la connexion URL en passant le proxy comme suggéré par NickDK fonctionne très bien.

//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);

Les propriétés système ne fonctionnent cependant pas comme je l'avais mentionné plus tôt.

Merci encore.

Cordialement, Keya

Keya
la source