在 Java 中验证 URL

Posted

技术标签:

【中文标题】在 Java 中验证 URL【英文标题】:Validating URL in Java 【发布时间】:2010-12-08 16:31:32 【问题描述】:

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

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

这可能是因为代理设置吗?我尝试设置代理的系统属性,但没有成功。

让我知道我做错了什么。

【问题讨论】:

这里好像有2个问题; URL 验证和查找 ConnectException 的原因 由于这是java url validator 的第一个谷歌点击,这里确实存在一些问题,如何验证 url(通过查看字符串)以及如何检查 url 是否可访问(通过例如 http 连接)。 【参考方案1】:

为了社区的利益,因为这个帖子在搜索时在 Google 上排名第一 "url 验证器 java"


捕获异常代价高昂,应尽可能避免。如果您只是想验证您的字符串是一个有效的 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");

【讨论】:

该 URLValidator 类被标记为已弃用。推荐的 URLValidator 在routines包中:commons.apache.org/validator/apidocs/org/apache/commons/… @Spektr 我已经修复了链接。谢谢。 我看不到这是标准 API UrlValidator 有自己的一组已知问题。是否有更积极维护的备用库? @AlexAverbuch:您能否概述一下 UrlValidator 的问题?只说它们存在而不说它们是什么并不是很有帮助。【参考方案2】:

java.net.URL 类实际上根本不是验证 URL 的好方法。 MalformedURLException 在构造过程中不会在所有格式错误的 URL 上抛出。在java.net.URL#openConnection().connect() 上捕获IOException 也不会验证 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。

【讨论】:

你找到解决这个问题的方法了吗?? @bi0s.kidd0 有几个库可以使用,但我们决定推出自己的。它不完整,但可以解析我们感兴趣的内容,包括包含域或 IP(v4 和 v6)的 URL。 github.com/jajja/arachne【参考方案3】:

您需要同时创建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

【讨论】:

请注意,有多种方法可以检查格式错误的网址/问题。例如,如果您将使用您的网址作为new HttpGet(url),那么如果存在格式错误的网址,您可以捕获IllegalArgumentException HttpGet(...) 抛出。如果获取数据有问题,HttpResponse 也会向你扔东西。 连接仅验证主机可用性。与 URL 的有效性无关。 MalformedURLException 不是测试 URL 有效形式的安全策略。这个答案具有误导性。 @Martin:你能详细说明为什么它不安全吗? 这是非常非常昂贵的。 openConnection/connect 实际上会尝试连接到 http 资源。这一定是我见过的最昂贵的 URL 验证方法之一。【参考方案4】:

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

例子:

public boolean isValidURL(String url) 

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

    return true;

【讨论】:

请注意,此字符串->url->uri 验证方案报告这些测试用例有效:“http://.com”“com”。 "ftp://::::@example.com" "http:/test.com" "http:test.com" "http:/:" 所以虽然这是标准 API,但它应用的验证规则可能不是期待什么。【参考方案5】:

有一种方法可以在不借助第三方库的情况下严格按照 Java 标准执行 URL 验证:

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

URI 的构造函数检查 url 是一个有效的 URI,并且对 parseServerAuthority 的调用确保它是一个 URL(绝对或相对)而不是 URN。

【讨论】:

抛出异常“如果此 URI 的权限组件已定义但不能根据 RFC 2396 解析为基于服务器的权限”。虽然这比大多数其他提案要好得多,但它无法验证 URL。 @Martin,您忘记了构造函数中的验证。正如我所写,URI 构造函数调用和parseServerAuthority 调用的组合验证了 URL,而不是单独的 parseServerAuthority 您可以在此页面上找到被您的建议错误验证的示例。请参阅文档,如果它不是为您的预期用途而设计的,请不要宣传利用它。 @Martin,你能说得更具体点吗?您认为哪些例子被这种方法错误地验证了? @Asu 是的。第二个://在主机之后,:引入端口号,根据语法可以为空。 // 是路径的一部分,有一个空段,也是有效的。如果您在浏览器中输入此地址,它会尝试打开它(但很可能找不到名为 https 的服务器;))。【参考方案6】:

在安卓上使用android.webkit.URLUtil

URLUtil.isValidUrl(URL_STRING);

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

【讨论】:

当然,只有当你正在使用 android 应用程序时。 它只检查 url 是否从正确的前缀开始:http://、https//、about: 等【参考方案7】:

重要的是要指出 URL 对象同时处理验证和连接。然后,只有在 sun.net.www.protocol 中提供了处理程序的协议才被授权(fileftpgopherhttphttpsjarmailto, netdoc) 是有效的。例如,尝试使用 ldap 协议创建一个新 URL:

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

您将收到java.net.MalformedURLException: unknown protocol: ldap

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

【讨论】:

【参考方案8】:

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

此外,如果您使用的是 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。【参考方案9】:

我认为最好的回应来自用户@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)(?:\\.\\d1,3)3)(?!(?:169\\.254|192\\.168)(?:\\.\\d1,3)2)(?!172\\.(?:1[6-9]|2\\d|3[0-1])(?:\\.\\d1,3)2)(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])(?:\\.(?:1?\\d1,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,))\\.?)(?::\\d2,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. 没有前缀的 URL 是无效的,(例如“***.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" 有效。【参考方案10】:

谢谢。按照 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);

但是,系统属性并不能像我之前提到的那样工作。

再次感谢。

问候, 可雅

【讨论】:

以上是关于在 Java 中验证 URL的主要内容,如果未能解决你的问题,请参考以下文章

Java中完美的URL验证正则表达式

java - 如何使用正则表达式验证Java中的URL? [复制]

JAVA 中的网站/URL 验证正则表达式

使用不正确的 url 验证 jdoconfig

在 JAVA 中通过身份验证后如何获取 okta 用户详细信息/当前会话

Java验证正则表达式