Überprüfen der URL in Java

103

Ich wollte wissen, ob es in Java Standard-APIs gibt, um eine bestimmte URL zu validieren. Ich möchte sowohl prüfen, ob die URL-Zeichenfolge richtig ist, dh das angegebene Protokoll gültig ist, als auch prüfen, ob eine Verbindung hergestellt werden kann.

Ich habe versucht, HttpURLConnection zu verwenden, die URL anzugeben und eine Verbindung herzustellen. Der erste Teil meiner Anforderung scheint erfüllt zu sein, aber wenn ich versuche, HttpURLConnection.connect () auszuführen, wird die Ausnahme 'java.net.ConnectException: Verbindung abgelehnt' ausgelöst.

Kann dies an den Proxy-Einstellungen liegen? Ich habe versucht, die Systemeigenschaften für den Proxy festzulegen, aber keinen Erfolg.

Lassen Sie mich wissen, was ich falsch mache.

Keya
quelle
2
Hier scheint es zwei Fragen zu geben; URL-Validierung und Auffinden der Ursache einer ConnectException
Ben James
Da dies der erste Google-Treffer für ist java url validator, gibt es hier tatsächlich Fragen, wie die URL überprüft werden kann (anhand der Zeichenfolge) und wie überprüft werden kann, ob die URL erreichbar ist (z. B. über eine http-Verbindung).
Wikingersteve

Antworten:

157

Zum Nutzen der Community, da dieser Thread bei der Suche nach
" url validator java " bei Google ganz oben steht.


Ausnahmen zu fangen ist teuer und sollte nach Möglichkeit vermieden werden. Wenn Sie nur überprüfen möchten, ob Ihre Zeichenfolge eine gültige URL ist, können Sie die UrlValidator- Klasse aus dem Apache Commons Validator- Projekt verwenden.

Beispielsweise:

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
quelle
37
Diese URLValidator-Klasse ist als veraltet markiert. Der empfohlene URLValidator befindet sich im Routinenpaket: commons.apache.org/validator/apidocs/org/apache/commons/…
Spektr
6
@Spektr Ich habe den Link behoben. Vielen Dank.
Yonatan
18
Ich kann nicht sehen, wie dies Standard-API ist
b1nary.atr0phy
2
UrlValidator hat seine eigenen bekannten Probleme. Gibt es eine alternative Bibliothek, die aktiver gepflegt wird?
Alex Averbuch
9
@AlexAverbuch: Können Sie bitte die Probleme mit UrlValidator skizzieren? Es ist nicht sehr hilfreich zu sagen, dass sie existieren, aber nicht zu sagen, was sie sind.
CDMckay
33

Sie müssen sowohl ein URLObjekt als auch ein URLConnectionObjekt erstellen . Der folgende Code testet sowohl das Format der URL als auch, ob eine Verbindung hergestellt werden kann:

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
quelle
Beachten Sie, dass es mehrere Möglichkeiten gibt, nach fehlerhaften URLs / Problemen zu suchen. Wenn Sie beispielsweise Ihre URL für a verwenden new HttpGet(url), können Sie die IllegalArgumentException HttpGet(...)Würfe abfangen, wenn eine fehlerhafte URL vorliegt. Und HttpResponsewirft auch Sachen auf dich, wenn es ein Problem mit dem Abrufen der Daten gibt.
Peter Ajtai
2
Die Verbindung überprüft nur die Verfügbarkeit des Hosts. Hat nichts mit der Gültigkeit der URL zu tun.
Andrey Rodionov
2
MalformedURLException ist keine sichere Strategie zum Testen der gültigen Form einer URL. Diese Antwort ist irreführend.
Martin
1
@ Martin: Kannst du erklären, warum es nicht sicher ist?
Jeroen Vannevel
28
Das ist sehr, sehr teuer. openConnection / connect versucht tatsächlich, eine Verbindung zur http-Ressource herzustellen. Dies muss eine der teuersten Methoden sein, die ich je gesehen habe, um eine URL zu überprüfen.
Glenn Bech
33

Die java.net.URLKlasse ist in der Tat überhaupt keine gute Möglichkeit, URLs zu validieren. MalformedURLExceptionwird während der Erstellung nicht auf alle fehlerhaften URLs geworfen. Fangen IOExceptionauf java.net.URL#openConnection().connect()nicht überprüft URL entweder nur sagen , ob oder nicht die Verbindung hergestellt werden kann.

Betrachten Sie diesen Code:

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

..die keine Ausnahmen wirft.

Ich empfehle die Verwendung einer Validierungs-API, die mit einer kontextfreien Grammatik implementiert wurde, oder bei einer sehr vereinfachten Validierung nur reguläre Ausdrücke. Ich brauche jedoch jemanden, der eine überlegene oder Standard-API dafür vorschlägt. Ich habe erst vor kurzem selbst damit begonnen, danach zu suchen.

Hinweis Es wurde vorgeschlagen, dass URL#toURI()in Kombination mit der Behandlung der Ausnahme java.net. URISyntaxExceptiondie Validierung von URLs erleichtert werden kann. Diese Methode erfasst jedoch nur einen der oben genannten sehr einfachen Fälle.

Die Schlussfolgerung ist, dass es keinen Standard-Java-URL-Parser zum Überprüfen von URLs gibt.

Martin
quelle
Haben Sie eine Lösung für dieses Problem gefunden?
kidd0
@ bi0s.kidd0 Es gibt mehrere Bibliotheken, die verwendet werden können, aber wir haben beschlossen, unsere eigenen zu rollen. Es ist nicht vollständig, kann aber analysieren, woran wir interessiert sind, einschließlich URLs, die entweder Domänen oder IPs enthalten (sowohl v4 als auch v6). github.com/jajja/arachne
Martin
15

Übergeben Sie die Zeichenfolge nur mit der Standard-API an ein URLObjekt und konvertieren Sie sie dann in ein URIObjekt. Dadurch wird die Gültigkeit der URL gemäß dem RFC2396-Standard genau bestimmt.

Beispiel:

public boolean isValidURL(String url) {

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

    return true;
}
b1nary.atr0phy
quelle
5
Beachten Sie, dass dieses String-> URL-> Uri-Validierungsschema meldet, dass diese Testfälle gültig sind: "http: //.com" " com ". "ftp: // :::: @ example.com" "http: /test.com" "http: test.com" "http: /:" Obwohl dies eine Standard-API ist, gelten die geltenden Validierungsregeln möglicherweise nicht was man erwartet.
DaveK
10

Verwenden Sie die android.webkit.URLUtilauf Android:

URLUtil.isValidUrl(URL_STRING);

Hinweis: Es wird nur das ursprüngliche URL-Schema überprüft, nicht, dass die gesamte URL gültig ist.

penduDev
quelle
2
Nur wenn Sie an einer Android-Anwendung arbeiten.
miva2
8

Es gibt eine Möglichkeit, die URL-Validierung in strikter Übereinstimmung mit den Standards in Java durchzuführen, ohne auf Bibliotheken von Drittanbietern zurückzugreifen:

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

Der Konstruktor der URIÜberprüfungen, bei dem urles sich um eine gültige URI handelt, und der Aufruf von parseServerAuthoritystellt sicher, dass es sich um eine URL (absolut oder relativ) und nicht um eine URN handelt.

dened
quelle
Die Ausnahme wird ausgelöst, wenn die Berechtigungskomponente dieses URI definiert ist, aber nicht als serverbasierte Berechtigung gemäß RFC 2396 analysiert werden kann. Dies ist zwar viel besser als die meisten anderen Vorschläge, kann jedoch keine URL validieren.
Martin
@ Martin, Sie haben die Validierung im Konstruktor vergessen. Wie ich geschrieben habe, validiert die Kombination aus URIKonstruktoraufruf und parseServerAuthorityAufruf die URL, nicht parseServerAuthorityallein.
Dened
1
Auf dieser Seite finden Sie Beispiele, die durch Ihren Vorschlag falsch validiert wurden. Weitere Informationen finden Sie in der Dokumentation. Wenn diese nicht für Ihren Verwendungszweck vorgesehen ist, bewerben Sie sie bitte nicht, um sie auszunutzen.
Martin
@ Martin, kannst du genauer sein? Welche Beispiele werden Ihrer Meinung nach mit dieser Methode falsch validiert?
Dened
1
@ Asu ja. Der zweite ://kommt, nachdem der Host :die Portnummer eingegeben hat, die je nach Syntax leer sein kann. //ist ein Teil des Pfades mit einem leeren Segment, was ebenfalls gültig ist. Wenn Sie diese Adresse in Ihren Browser eingeben, wird versucht, sie zu öffnen (der Server mit dem Namen wird jedoch höchstwahrscheinlich nicht gefunden https;)).
Dened
2

Es ist nur wichtig darauf hinzuweisen, dass das URL-Objekt sowohl die Validierung als auch die Verbindung übernimmt. Dann sind nur Protokolle gültig, für die in sun.net.www.protocol ein Handler bereitgestellt wurde ( Datei , FTP , Gopher , http , https , jar , mailto , netdoc ). Versuchen Sie beispielsweise, eine neue URL mit dem ldap- Protokoll zu erstellen :

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

Du wirst eine bekommen java.net.MalformedURLException: unknown protocol: ldap.

Sie müssen Ihren eigenen Handler implementieren und über registrieren URL.setURLStreamHandlerFactory(). Wenn Sie nur die URL-Syntax überprüfen möchten, scheint ein regulärer Ausdruck eine einfachere Lösung zu sein.

Doc Davluz
quelle
1

Sind Sie sicher, dass Sie den richtigen Proxy als Systemeigenschaften verwenden?

Wenn Sie 1.5 oder 1.6 verwenden, können Sie auch eine java.net.Proxy-Instanz an die openConnection () -Methode übergeben. Das ist eleganter 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);
NickDK
quelle
Warum sollte das elegant oder sogar richtig sein? Es verwendet teure Ressourcen, wenn es funktioniert, und es funktioniert nicht, wenn eine korrekte URL beim Testen nicht für die Verbindung verfügbar ist.
Martin
0

Ich denke, die beste Antwort kommt vom Benutzer @ b1nary.atr0phy. Irgendwie empfehle ich, die Methode aus der Antwort b1nay.atr0phy mit einem regulären Ausdruck zu kombinieren, um alle möglichen Fälle abzudecken.

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
quelle
1
Es gibt einige Probleme mit dieser Regex: 1. URLs ohne Präfix sind ungültig (z. B. "stackoverflow.com"). Dies schließt auch URLs mit zwei Suffixen ein, wenn das Präfix fehlt (z. B. "amazon.co.uk") "). 2. IPs sind immer ungültig (z. B. " 127.0.0.1" ), unabhängig davon, ob sie das Präfix verwenden oder nicht. Ich würde vorschlagen, "((http|https|ftp)://)?((\\w)*|([0-9]*)|([-|_])*)+([\\.|/]((\\w)*|([0-9]*)|([-|_])*))+"( Quelle ) zu verwenden. Der einzige Nachteil dieser Regex ist, dass zB "127.0..0.1" und "127.0" gültig sind.
Neph
-2

Vielen Dank. Das Öffnen der URL-Verbindung durch Übergeben des von NickDK vorgeschlagenen Proxys funktioniert einwandfrei.

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

Die Systemeigenschaften funktionieren jedoch nicht wie zuvor erwähnt.

Danke noch einmal.

Grüße, Keya

Keya
quelle