在 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 中提供了处理程序的协议才被授权(file, ftp、gopher、http、https、jar、mailto, 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 - 如何使用正则表达式验证Java中的URL? [复制]