验证Java中的URL


103

我想知道Java中是否有标准API可以验证给定的URL?我想检查URL字符串是否正确(即给定的协议有效),然后检查是否可以建立连接。

我尝试使用HttpURLConnection,提供URL并连接到它。我的要求的第一部分似乎已得到满足,但是当我尝试执行HttpURLConnection.connect()时,抛出了“ java.net.ConnectException:连接被拒绝”异常。

难道是因为代理设置?我尝试为代理设置系统属性,但没有成功。

让我知道我在做什么错。


2
这里似乎有两个问题。URL验证并查找ConnectException的原因
Ben James

由于这是google的第一个命中方法java url validator,这里确实存在一些问题,如何验证url(通过查看字符串)以及如何检查url是否可访问(例如,通过http连接)。
vikingsteve

Answers:


157

为了社区的利益,由于此线程在搜索
url validateator java ” 时在Google上排名第一


捕获异常的代价很高,应尽可能避免。如果只想验证String是有效的URL,则可以使用Apache Commons Validator项目中的UrlValidator类。

例如:

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
该URLValidator类被标记为已弃用。推荐的URLValidator在例程包中:commons.apache.org/validator/apidocs/org/apache/commons/…–
Spektr

6
@Spektr我已经修复了链接。谢谢。
Yonatan

18
我看不到这是标准的API
b1nary.atr0phy

2
UrlValidator有其自己的一组已知问题。是否有一个更积极地维护的备用库?
Alex Averbuch

9
@AlexAverbuch:您能概述一下UrlValidator的问题吗?仅仅说它们存在而不是说它们是什么不是很有帮助。
cdmckay,2015年

33

您需要创建一个URL对象和一个URLConnection对象。以下代码将测试URL的格式以及是否可以建立连接:

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
}

请注意,有多种方法可以检查格式错误的网址/问题。例如,如果您将URL用作new HttpGet(url),则IllegalArgumentException HttpGet(...)如果URL格式错误,则可以引发异常。并且HttpResponse将在你身上的东西太多,如果有一个与获取数据的问题。
2011年

2
连接仅验证主机可用性。与URL的有效性无关。
Andrey Rodionov

2
MalformedURLException不是测试URL有效形式的安全策略。这个答案是误导的。
马丁

1
@马丁:您能详细说明为什么它不安全吗?
Jeroen Vannevel 2014年

28
这非常非常昂贵。openConnection / connect实际上将尝试连接到http资源。这肯定是我见过的用于验证URL的最昂贵的方法之一。
Glenn Bech 2014年

33

java.net.URL实际上,该类根本不是验证URL的好方法。MalformedURLException不是扔在施工期间的所有格式不正确的URL。追赶IOExceptionjava.net.URL#openConnection().connect()不验证URL要么,只能告诉羯羊或不是可以建立连接。

考虑这段代码:

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

..不会引发任何异常。

我建议使用一些使用上下文无关语法实现的验证API,或者在非常简化的验证中仅使用正则表达式。但是,我需要有人为此建议一个高级或标准的API,我直到最近才开始自己寻找它。

注意 建议将其URL#toURI()与异常处理结合使用,java.net. URISyntaxException可以简化URL的验证。但是,此方法仅捕获上述非常简单的情况之一。

结论是,没有标准的Java URL解析器来验证URL。


您找到解决此问题的方法了吗?
kidd0 2014年

@ bi0s.kidd0有几个可以使用的库,但是我们决定使用自己的库。它并不完整,但是可以解析我们感兴趣的内容,包括包含域或IP(v4和v6)的URL。github.com/jajja/arachne
Martin

15

使用标准API,将字符串传递给URL对象,然后将其转换为URI对象。这将根据RFC2396标准准确确定URL的有效性。

例:

public boolean isValidURL(String url) {

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

    return true;
}

5
请注意,此string-> url-> uri验证方案报告这些测试用例有效:“ http://.com”“ com。” “ ftp:// :::: @ example.com”“ http:/test.com”“ http:test.com”“ http:/:”因此,虽然这是标准API,但可能不适用所应用的验证规则人们期望什么。
DaveK

10

android.webkit.URLUtil在android上使用:

URLUtil.isValidUrl(URL_STRING);

注意:这只是检查URL的初始方案,而不是整个URL有效。


2
仅当您在课程的android应用程序上工作时。
miva2

8

有一种方法可以严格按照Java中的标准执行URL验证,而无需借助第三方库:

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

URIcheck 的构造函数url是有效的URI,并对其进行调用以parseServerAuthority确保它是URL(绝对或相对)而不是URN。


引发异常“如果已定义此URI的权限组件,但根据RFC 2396无法将其解析为基于服务器的权限”。尽管这比大多数其他建议要好得多,但它无法验证URL。
马丁

@Martin,您忘记了构造函数中的验证。如我所写,URI构造函数调用和parseServerAuthority调用的组合不仅可以parseServerAuthority单独验证URL 。
拒绝了

1
您可以在此页面上找到您的建议未正确验证的示例。请参考文档,如果它不是为您的预期用途而设计的,请不要推广使用它。
马丁

@马丁,你能更具体一点吗?您认为该方法错误地验证了哪些示例?
dened

1
@Asu是的。第二个://出现在主机之后,:介绍了端口号,根据语法可以为空。//是路径中具有空段的一部分,这也是有效的。如果在浏览器中输入此地址,它将尝试将其打开(但很可能找不到名为https; 的服务器)。
否定

2

仅需指出URL对象既可以处理验证也可以处理连接。然后,仅授权在sun.net.www.protocol中提供处理程序的协议(fileftpgopherhttphttpsjarmailtonetdoc)是有效的协议。例如,尝试使用ldap协议创建新的URL :

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

你会得到一个java.net.MalformedURLException: unknown protocol: ldap

您需要实现自己的处理程序并通过进行注册URL.setURLStreamHandlerFactory()。如果您只想验证URL语法,就显得有些矫over过正,正则表达式似乎是一个更简单的解决方案。


1

您确定使用正确的代理作为系统属性吗?

同样,如果您使用的是1.5或1.6,则可以将java.net.Proxy实例传递给openConnection()方法。这是更优雅的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);

为什么这会优雅甚至正确?它在工作时会使用昂贵的资源,并且无法正常工作,因为测试时无法使用正确的URL进行连接。
马丁

0

我认为最好的响应是来自用户@ b1nary.atr0phy。我建议以某种方式将b1nay.atr0phy响应中的方法与正则表达式结合使用,以涵盖所有可能的情况。

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
此正则表达式有两个问题:1.没有前缀的URL无效(例如“ stackoverflow.com”),如果缺少前缀,则还包括带有两个后缀的URL(例如“ amazon.co.uk”) ”)。2. IP总是无效的(例如“ 127.0.0.1”),无论它们是否使用前缀。我建议使用"((http|https|ftp)://)?((\\w)*|([0-9]*)|([-|_])*)+([\\.|/]((\\w)*|([0-9]*)|([-|_])*))+"source)。该正则表达式的唯一缺点是例如“ 127.0..0.1”和“ 127.0”有效。
Neph

-2

谢谢。按照NickDK的建议通过传递代理来打开URL连接可以正常工作。

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

但是,系统属性无法像我前面提到的那样工作。

再次感谢。

此致,科亚

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.