Validando URL en Java

103

Quería saber si hay alguna API estándar en Java para validar una URL determinada. Quiero comprobar si la cadena de URL es correcta, es decir, el protocolo dado es válido y luego comprobar si se puede establecer una conexión.

Intenté usar HttpURLConnection, proporcioné la URL y me conecté a ella. La primera parte de mi requisito parece cumplirse, pero cuando intento realizar HttpURLConnection.connect (), se lanza la excepción 'java.net.ConnectException: Conexión rechazada'.

¿Puede esto deberse a la configuración del proxy? Intenté configurar las propiedades del sistema para el proxy pero no tuve éxito.

Déjame saber qué estoy haciendo mal.

Keya
fuente
2
Parece que hay 2 preguntas aquí; Validación de URL y búsqueda de la causa de una ConnectException
Ben James
Dado que este es el primer acceso de Google para java url validator, de hecho, hay preguntas aquí, cómo validar la URL (mirando la cadena) y cómo verificar si la URL es accesible (a través de una conexión http, por ejemplo).
vikingsteve

Respuestas:

157

Para beneficio de la comunidad, ya que este hilo es el primero en Google cuando se busca
" url validator java "


La captura de excepciones es costosa y debe evitarse cuando sea posible. Si solo desea verificar que su String es una URL válida, puede usar la clase UrlValidator del proyecto Apache Commons Validator .

Por ejemplo:

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
fuente
37
Esa clase URLValidator está marcada en desuso. El URLValidator recomendado está en el paquete de rutinas: commons.apache.org/validator/apidocs/org/apache/commons/…
Spektr
6
@Spektr He arreglado el enlace. Gracias.
Yonatan
18
No veo cómo esto es API estándar
b1nary.atr0phy
2
UrlValidator tiene su propio conjunto de problemas conocidos. ¿Existe una biblioteca alternativa que se mantenga de manera más activa?
Alex Averbuch
9
@AlexAverbuch: ¿puede describir cuáles son los problemas con UrlValidator? No es muy útil decir simplemente que existen, pero no decir lo que son.
cdmckay
33

Necesita crear un URLobjeto y un URLConnectionobjeto. El siguiente código probará tanto el formato de la URL como si se puede establecer una conexión:

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
fuente
Tenga en cuenta que hay varias formas de comprobar si hay problemas o URL con formato incorrecto. Por ejemplo, si va a utilizar su URL para a new HttpGet(url), puede detectar los IllegalArgumentException HttpGet(...)lanzamientos si hay una URL mal formada. Y también le HttpResponsearrojará cosas si hay un problema para obtener los datos.
Peter Ajtai
2
La conexión solo valida la disponibilidad del host. No tiene nada que ver con la validez de la URL.
Andrey Rodionov
2
MalformedURLException no es una estrategia segura para probar la forma válida de una URL. Esta respuesta es engañosa.
Martin
1
@Martin: ¿puedes explicar por qué no es seguro?
Jeroen Vannevel
28
Esto es muy, muy caro. openConnection / connect realmente intentará conectarse al recurso http. Esta debe ser una de las formas más caras que he visto de verificar una URL.
Glenn Bech
33

De hecho, la java.net.URLclase no es en absoluto una buena forma de validar URL. MalformedURLExceptionse no tirado en todas las direcciones URL mal formados durante la construcción. La captura IOExceptionde java.net.URL#openConnection().connect()no valida URL o bien, sólo cuentan tiempo o no se puede establecer la conexión.

Considere este fragmento de código:

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

..que no arroja ninguna excepción.

Recomiendo usar alguna API de validación implementada usando una gramática libre de contexto, o en una validación muy simplificada, simplemente use expresiones regulares. Sin embargo, necesito que alguien sugiera una API superior o estándar para esto, solo recientemente comencé a buscarla yo mismo.

Nota Se ha sugerido que URL#toURI()en combinación con el manejo de la excepción java.net. URISyntaxExceptionpuede facilitar la validación de URL. Sin embargo, este método solo detecta uno de los casos muy simples anteriores.

La conclusión es que no existe un analizador de URL estándar de Java para validar las URL.

Martín
fuente
¿Ha encontrado una solución a este problema?
kidd0
@ bi0s.kidd0 Hay varias bibliotecas que se pueden usar, pero decidimos lanzar la nuestra. No está completo, pero puede analizar lo que nos interesa, incluidas las URL que contienen dominios o IP (tanto v4 como v6). github.com/jajja/arachne
Martin
15

Utilizando solo una API estándar, pase la cadena a un URLobjeto y luego conviértala en un URIobjeto. Esto determinará con precisión la validez de la URL de acuerdo con el estándar RFC2396.

Ejemplo:

public boolean isValidURL(String url) {

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

    return true;
}
b1nary.atr0phy
fuente
5
Tenga en cuenta que este esquema de validación string-> url-> uri informa que estos casos de prueba son válidos: "http: //.com" " com ". "ftp: // :::: @ example.com" "http: /test.com" "http: test.com" "http: /:" Entonces, si bien esta es una API estándar, las reglas de validación que aplica pueden no ser lo que uno espera.
DaveK
10

Utilice el android.webkit.URLUtilen Android:

URLUtil.isValidUrl(URL_STRING);

Nota: es solo verificar el esquema inicial de la URL, no que toda la URL sea válida.

penduDev
fuente
2
Solo si está trabajando en una aplicación de Android, por supuesto.
miva2
8

Existe una forma de realizar la validación de URL estrictamente de acuerdo con los estándares en Java sin recurrir a bibliotecas de terceros:

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

El constructor de URIverifica que urlsea ​​un URI válido, y la llamada a parseServerAuthorityasegura que sea un URL (absoluto o relativo) y no un URN.

definido
fuente
Se lanza la excepción "Si el componente de autoridad de este URI está definido pero no se puede analizar como una autoridad basada en servidor de acuerdo con RFC 2396". Si bien esto es mucho mejor que la mayoría de las otras propuestas, no puede validar una URL.
Martin
@Martin, te olvidaste de la validación en el constructor. Como escribí, la combinación de la URIllamada al constructor y la parseServerAuthorityllamada valida la URL, no parseServerAuthoritysolo.
definido el
1
Puede encontrar ejemplos en esta página que están validados incorrectamente por su sugerencia. Consulte la documentación y, si no está diseñada para su uso previsto, no promocione su explotación.
Martin
@Martin, ¿puedes ser más específico? ¿Qué ejemplos en su opinión están validados incorrectamente por este método?
definido
1
@Asu sí. El segundo ://viene después del host, :introduce el número de puerto, que puede estar vacío según la sintaxis. //es una parte de la ruta con un segmento vacío, que también es válido. Si ingresa esta dirección en su navegador, intentará abrirla (pero lo más probable es que no encuentre el servidor llamado https;)).
definido el
2

Solo es importante señalar que el objeto URL maneja tanto la validación como la conexión. Entonces, solo los protocolos para los que se ha proporcionado un controlador en sun.net.www.protocol están autorizados ( archivo , ftp , gopher , http , https , jar , mailto , netdoc ) son válidos. Por ejemplo, intente crear una nueva URL con el protocolo ldap :

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

Obtendrá un java.net.MalformedURLException: unknown protocol: ldap.

Necesita implementar su propio controlador y registrarlo URL.setURLStreamHandlerFactory(). Bastante exagerado si solo desea validar la sintaxis de la URL, una expresión regular parece ser una solución más simple.

Doc Davluz
fuente
1

¿Está seguro de que está utilizando el proxy correcto como propiedades del sistema?

Además, si está utilizando 1.5 o 1.6, puede pasar una instancia de java.net.Proxy al método openConnection (). Esto es más elegante en mi opinión:

//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
fuente
¿Por qué sería esto elegante o incluso correcto? Utiliza recursos costosos cuando funciona y no funciona porque una URL correcta no está disponible para la conexión cuando se prueba.
Martin
0

Creo que la mejor respuesta es del usuario @ b1nary.atr0phy. De alguna manera, recomiendo combinar el método de la respuesta b1nay.atr0phy con una expresión regular para cubrir todos los casos posibles.

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
fuente
1
Hay un par de problemas con esta expresión regular: 1. Las URL sin el prefijo no son válidas (por ejemplo, "stackoverflow.com"), esto también incluye las URL con dos sufijos si les falta el prefijo (por ejemplo, "amazon.co.uk "). 2. Las direcciones IP siempre son inválidas (por ejemplo, " 127.0.0.1" ), sin importar si usan el prefijo o no. Sugeriría usar "((http|https|ftp)://)?((\\w)*|([0-9]*)|([-|_])*)+([\\.|/]((\\w)*|([0-9]*)|([-|_])*))+"( fuente ). El único inconveniente de esta expresión regular es que, por ejemplo, "127.0..0.1" y "127.0" son válidos.
Neph
-2

Gracias. Abrir la conexión URL pasando el Proxy como lo sugiere NickDK funciona 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);

Sin embargo, las propiedades del sistema no funcionan como mencioné anteriormente.

Gracias de nuevo.

Saludos, Keya

Keya
fuente