Convalida dell'URL in Java


103

Volevo sapere se esistono API standard in Java per convalidare un determinato URL? Voglio controllare entrambi se la stringa dell'URL è corretta, cioè il protocollo dato è valido, e poi controllare se è possibile stabilire una connessione.

Ho provato a utilizzare HttpURLConnection, fornendo l'URL e connettendomi ad esso. La prima parte del mio requisito sembra essere soddisfatta, ma quando provo a eseguire HttpURLConnection.connect (), viene generata l'eccezione "java.net.ConnectException: connessione rifiutata".

Può essere a causa delle impostazioni del proxy? Ho provato a impostare le proprietà di sistema per il proxy ma senza successo.

Fammi sapere cosa sto sbagliando.


2
Sembra che ci siano 2 domande qui; Convalida dell'URL e individuazione della causa di una ConnectException
Ben James,

Poiché questo è il primo hit di Google per java url validator, ci sono davvero delle domande qui, come convalidare l'URL (guardando la stringa) e come verificare se l'URL è raggiungibile (tramite una connessione http, ad esempio).
vikingsteve

Risposte:


157

A vantaggio della comunità, poiché questo thread è in cima a Google quando si cerca
" url validator java "


Catturare le eccezioni è costoso e dovrebbe essere evitato quando possibile. Se vuoi solo verificare che la tua stringa sia un URL valido, puoi usare la classe UrlValidator dal progetto Apache Commons Validator .

Per esempio:

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
Quella classe URLValidator è contrassegnata come deprecata. L'URLValidator consigliato si trova nel pacchetto delle routine: commons.apache.org/validator/apidocs/org/apache/commons/…
Spektr

6
@Spektr ho corretto il collegamento. Grazie.
Yonatan

18
Non riesco a vedere come questa sia API standard
b1nary.atr0phy

2
UrlValidator ha una propria serie di problemi noti. Esiste una libreria alternativa che viene mantenuta più attivamente?
Alex Averbuch

9
@AlexAverbuch: puoi delineare per favore quali sono i problemi con UrlValidator? Non è molto utile dire solo che esistono ma non dire cosa sono.
cdmckay

33

Devi creare sia un URLoggetto che un URLConnectionoggetto. Il codice seguente verificherà sia il formato dell'URL sia se è possibile stabilire una connessione:

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
}

Tieni presente che esistono diversi modi per verificare la presenza di URL / problemi non corretti. Ad esempio, se utilizzerai il tuo URL per un new HttpGet(url), allora puoi prendere i IllegalArgumentException HttpGet(...)lanci se c'è un URL non valido. E HttpResponseti lancia qualcosa anche se c'è un problema con il recupero dei dati.
Peter Ajtai

2
La connessione convalida solo la disponibilità dell'host. Non ha nulla a che fare con la validità dell'URL.
Andrey Rodionov

2
MalformedURLException non è una strategia sicura per testare la forma valida di un URL. Questa risposta è fuorviante.
Martin

1
@ Martin: puoi spiegare perché non è sicuro?
Jeroen Vannevel

28
Questo è molto, molto costoso. openConnection / connect proverà effettivamente a connettersi alla risorsa http. Questo deve essere uno dei modi più costosi che abbia mai visto per verificare un URL.
Glenn Bech

33

La java.net.URLclasse infatti non è affatto un buon modo per convalidare gli URL. nonMalformedURLException viene generato su tutti gli URL non corretti durante la costruzione. Facendo il non convalida URL o, dica solo castrato o no la connessione può essere stabilita.IOExceptionjava.net.URL#openConnection().connect()

Considera questo pezzo di codice:

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

..che non genera eccezioni.

Consiglio di utilizzare alcune API di convalida implementate utilizzando una grammatica libera dal contesto o, in una convalida molto semplificata, utilizzare semplicemente espressioni regolari. Tuttavia ho bisogno che qualcuno suggerisca un'API superiore o standard per questo, ho iniziato a cercarla solo di recente.

Nota È stato suggerito che URL#toURI()in combinazione con la gestione dell'eccezione java.net. URISyntaxExceptionpuò facilitare la convalida degli URL. Tuttavia, questo metodo cattura solo uno dei casi molto semplici sopra.

La conclusione è che non esiste un parser URL java standard per convalidare gli URL.


Hai trovato una soluzione a questo problema ??
kidd0

@ bi0s.kidd0 Esistono diverse librerie che possono essere utilizzate, ma abbiamo deciso di lanciarne una nostra. Non è completo, ma può analizzare ciò che ci interessa, inclusi gli URL contenenti domini o IP (sia v4 che v6). github.com/jajja/arachne
Martin

15

Utilizzando solo l'API standard, passa la stringa a un URLoggetto, quindi convertila in un URIoggetto. Ciò determinerà accuratamente la validità dell'URL in base allo standard RFC2396.

Esempio:

public boolean isValidURL(String url) {

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

    return true;
}

5
Nota che questo schema di convalida stringa-> url-> uri segnala che questi casi di test sono validi: "http: //.com" " com ". "ftp: // :::: @ example.com" "http: /test.com" "http: test.com" "http: /:" Quindi, sebbene questa sia un'API standard, le regole di convalida che applica potrebbero non essere quello che ci si aspetta.
DaveK

10

Usa android.webkit.URLUtilsu Android:

URLUtil.isValidUrl(URL_STRING);

Nota: sta solo controllando lo schema iniziale dell'URL, non che l'intero URL sia valido.


2
Solo se stai lavorando su un'applicazione Android, naturalmente.
miva2

8

C'è un modo per eseguire la convalida dell'URL in stretta conformità agli standard in Java senza ricorrere a librerie di terze parti:

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

Il costruttore di URIcontrolli che urlè un URI valido e la chiamata a parseServerAuthorityassicura che si tratti di un URL (assoluto o relativo) e non di un URN.


Viene generata l'eccezione "Se il componente di autorità di questo URI è definito ma non può essere analizzato come un'autorità basata sul server secondo RFC 2396". Sebbene sia molto meglio della maggior parte delle altre proposte, non può convalidare un URL.
Martin

@ Martin, ti sei dimenticato della convalida nel costruttore. Come ho scritto, la combinazione della URIchiamata al costruttore e della parseServerAuthoritychiamata convalida l'URL, non parseServerAuthorityda sola.
negato il

1
In questa pagina puoi trovare esempi convalidati in modo errato dal tuo suggerimento. Fare riferimento alla documentazione e, se non è progettata per l'uso previsto, non promuovere per sfruttarla.
Martin

@ Martin, puoi essere più specifico? Quali esempi secondo te sono validati in modo errato da questo metodo?
negato

1
@Asu sì. Il secondo ://viene dopo l'host, :introduce il numero di porta, che può essere vuoto secondo la sintassi. //è una parte del percorso con un segmento vuoto, anch'esso valido. Se inserisci questo indirizzo nel tuo browser, proverà ad aprirlo (ma molto probabilmente non troverà il server denominato https;)).
negato il

2

È solo importante sottolineare che l'oggetto URL gestisce sia la convalida che la connessione. Quindi, solo i protocolli per i quali è stato fornito un gestore in sun.net.www.protocol sono autorizzati ( file , ftp , gopher , http , https , jar , mailto , netdoc ) sono quelli validi. Ad esempio, prova a creare un nuovo URL con il protocollo ldap :

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

Otterrai un file java.net.MalformedURLException: unknown protocol: ldap.

È necessario implementare il proprio gestore e registrarlo tramite URL.setURLStreamHandlerFactory(). Abbastanza eccessivo se vuoi solo convalidare la sintassi dell'URL, una regexp sembra essere una soluzione più semplice.


1

Sei sicuro di utilizzare il proxy corretto come proprietà di sistema?

Inoltre, se stai usando 1.5 o 1.6 potresti passare un'istanza java.net.Proxy al metodo openConnection (). Questo è più elegante 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);

Perché questo dovrebbe essere elegante o addirittura corretto? Utilizza risorse costose quando funziona e non funziona perché un URL corretto non è disponibile per la connessione durante il test.
Martin

0

Penso che la risposta migliore sia da parte dell'utente @ b1nary.atr0phy. In qualche modo, consiglio di combinare il metodo dalla risposta b1nay.atr0phy con una regex per coprire tutti i casi possibili.

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
Ci sono un paio di problemi con questa regex: 1. Gli URL senza il prefisso non sono validi, (ad esempio "stackoverflow.com"), questo include anche gli URL con due suffissi se manca il prefisso (ad esempio "amazon.co.uk "). 2. Gli IP sono sempre non validi (ad es. " 127.0.0.1" ), indipendentemente dal fatto che utilizzino o meno il prefisso. Suggerirei di usare "((http|https|ftp)://)?((\\w)*|([0-9]*)|([-|_])*)+([\\.|/]((\\w)*|([0-9]*)|([-|_])*))+"( fonte ). L'unico aspetto negativo di questa regex è che, ad esempio, "127.0..0.1" e "127.0" sono validi.
Neph

-2

Grazie. L'apertura della connessione URL passando il proxy come suggerito da NickDK funziona bene.

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

Le proprietà di sistema tuttavia non funzionano come avevo accennato in precedenza.

Grazie ancora.

Saluti, Keya

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.