2010-06-29 8 views
4

Mon application traite les URL saisies manuellement par les utilisateurs. J'ai découvert que certaines URL mal formées (telles que 'http:/non-valide') entraînent le rejet de NullPointerException lors de l'ouverture de la connexion. Comme j'ai appris de this Java bug report, le problème est connu et ne sera pas corrigé. La suggestion est d'utiliser java.net.URI, qui est "plus conforme à la RFC 2396".Comment vérifier que l'URL est valide dans Java 1.6?

La question est: comment utiliser URI pour contourner le problème? La seule chose que je peux faire avec URI est de l'utiliser pour analyser la chaîne et générer des URL. J'ai préparé le programme suivant:

import java.net.*; 

public class Test 
{ 
    public static void main(String[] args) 
    { 
     try { 
      URI uri = URI.create(args[0]); 
      Object o = uri.toURL().getContent(); // try to get content 
     } 
     catch(Throwable e) { 
      e.printStackTrace(); 
     } 
    } 
} 

Voici les résultats de mes tests (avec Java 1.6.0_20), pas très différent de ce que je reçois avec java.net.URL:

 
sh-3.2$ java Test url-not-valid 
java.lang.IllegalArgumentException: URI is not absolute 
     at java.net.URI.toURL(URI.java:1080) 
     at Test.main(Test.java:9) 
sh-3.2$ java Test http:/url-not-valid 
java.lang.NullPointerException 
     at sun.net.www.ParseUtil.toURI(ParseUtil.java:261) 
     at sun.net.www.protocol.http.HttpURLConnection.plainConnect(HttpURLConnection.java:795) 
     at sun.net.www.protocol.http.HttpURLConnection.connect(HttpURLConnection.java:726) 
     at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1049) 
     at java.net.URLConnection.getContent(URLConnection.java:688) 
     at java.net.URL.getContent(URL.java:1024) 
     at Test.main(Test.java:9) 
sh-3.2$ java Test http:///url-not-valid 
java.lang.IllegalArgumentException: protocol = http host = null 
     at sun.net.spi.DefaultProxySelector.select(DefaultProxySelector.java:151) 
     at sun.net.www.protocol.http.HttpURLConnection.plainConnect(HttpURLConnection.java:796) 
     at sun.net.www.protocol.http.HttpURLConnection.connect(HttpURLConnection.java:726) 
     at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1049) 
     at java.net.URLConnection.getContent(URLConnection.java:688) 
     at java.net.URL.getContent(URL.java:1024) 
     at Test.main(Test.java:9) 
sh-3.2$ java Test http:////url-not-valid 
java.lang.NullPointerException 
     at sun.net.www.ParseUtil.toURI(ParseUtil.java:261) 
     at sun.net.www.protocol.http.HttpURLConnection.plainConnect(HttpURLConnection.java:795) 
     at sun.net.www.protocol.http.HttpURLConnection.connect(HttpURLConnection.java:726) 
     at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1049) 
     at java.net.URLConnection.getContent(URLConnection.java:688) 
     at java.net.URL.getContent(URL.java:1024) 
     at Test.main(Test.java:9) 
+0

Il devrait être Java 6 - Java 1.6 n'est plus utilisé officiellement. –

+0

@ Péter Török Que vous dit java -version? La mienne dit 'version java '1.6.0_20" ' –

+0

@Pete Kirkham, OTOH Je ne trouve pas de" JDK 1.6 "sur [Site Java de Sun] (http://java.sun.com/javase/downloads/index. jsp). –

Répondre

1

Vous pouvez utiliser Appache Validator Commons ..

UrlValidator urlValidator = new UrlValidator(); 
urlValidator.isValid("http://google.com"); 

http://commons.apache.org/validator/

http://commons.apache.org/validator/api-1.3.1/

+0

Je vais vérifier celui-là. Mon sentiment est le suivant: si l'utilisation d'un validateur externe est la seule façon d'utiliser correctement java.net.URL/URI, je dirais que le comportement que j'ai décrit est un bug qui rend ces classes inutilisables - ce serait vraiment étrange pour un standard classe. Peut-être que je ne connais pas certains détails importants/condition préalable à l'utilisation? –

1

Si je exécutez votre code avec le type d'URI mal formé dans le rapport de bug puis il lance URISyntaxException. Ainsi, le correctif suggéré corrige l'erreur signalée.

$ java -cp bin UriTest http:\\\\www.google.com\\ 
java.lang.IllegalArgumentException 
    at java.net.URI.create(URI.java:842) 
    at UriTest.main(UriTest.java:8) 
Caused by: java.net.URISyntaxException: Illegal character in opaque part at index 5: http:\\www.google.com\ 
    at java.net.URI$Parser.fail(URI.java:2809) 
    at java.net.URI$Parser.checkChars(URI.java:2982) 
    at java.net.URI$Parser.parse(URI.java:3019) 
    at java.net.URI.(URI.java:578) 
    at java.net.URI.create(URI.java:840) 

Votre type d'URI mal formé est différent et ne semble pas être une erreur de syntaxe. Au lieu de cela, attraper l'exception de pointeur null et récupérer avec un message approprié.

Vous pouvez essayer d'être amical et vérifier si l'URI commence par une barre oblique « http:/» et suggèrent que pour l'utilisateur, ou vous pouvez vérifier si le nom d'hôte de l'URL est non vide:

import java.net.*; 

public class UriTest 
{ 
    public static void main (String[] args) 
    { 
     try { 
      URI uri = URI.create (args[0]); 

      // avoid null pointer exception 
      if (uri.getHost() == null) 
       throw new MalformedURLException ("no hostname"); 

      URL url = uri.toURL(); 
      URLConnection s = url.openConnection(); 

      s.getInputStream(); 
     } catch (Throwable e) { 
      e.printStackTrace(); 
     } 
    } 
} 
+0

Je ne veux pas vérifier tous les problèmes d'URL manuellement, puisque je comprends cela est exactement ce que l'URL/URI devrait faire pour moi (si je me trompe ici, cela peut être un indice de ce que je devrais faire). Attraper l'exception d'exécution ici est un hack moche que je considère à appliquer si tout le reste échoue, mais en général l'idée est mauvaise - il peut cacher d'autres erreurs fatales se produisant pendant la connexion. Je crois qu'une meilleure solution devrait exister. –

+0

@ Bartłomiej Kalinowski URI * fait * le contrôle pour vous - si le nom de l'hôte est null (URI.getHost() == null lorsque URL.getHost(). Est égal à ("")) alors il lance un NPE pour signifier que vous êtes connecté à un hôte nul. NPE peut éventuellement cacher d'autres erreurs, mais qu'espérais-tu faire dans ces cas? Quelle que soit l'erreur, vous devez probablement demander à l'utilisateur de corriger/réessayer/annuler, donc la distinction n'est pas très importante - peut-être la différence entre les exceptions d'E/S et d'autres exceptions - vous pouvez réessayer automatiquement sur erreur E/S mais pas sur autres. –

+0

Je dois détecter que l'URL est erronée, et distinguer ce problème de tous les autres problèmes comme les erreurs d'E/S etc. L'application n'interagit pas avec l'utilisateur, donc je ne peux pas demander à l'utilisateur de réessayer/corriger, et je peux m'attendre est faux (même s'il a été validé auparavant). –

0

Notez que même avec les approches proposées dans les autres réponses, vous n'obtiendrez pas la validation correcte, puisque java.net.URI adhère à la RFC 2396, ce qui est notamment obsolète. En utilisant java.net.URI, vous obtiendrez des exceptions pour les URL qui sont aujourd'hui valables pour tous les navigateurs Web.

Afin de résoudre ces problèmes, j'ai écrit une bibliothèque pour l'analyse d'URL en Java: galimatias. Il exécute l'analyse d'URL de la même manière que les navigateurs web (adhérant au WHATWG URL Specification).

Dans votre cas, vous pouvez écrire:

try { 
    URL url = io.mola.galimatias.URL.parse(url).toJavaURL(); 
} catch (GalimatiasParseException e) { 
    // If this exception is thrown, the given URL contains a unrecoverable error. That is, it's completely invalid. 
} 

Comme un beau effet secondaire, vous obtenez beaucoup de sanitization que vous ne serez pas avec java.net.URI. Par exemple, http:/example.com sera correctement analysé comme http://example.com/.

Questions connexes