如何在Java中检查有效的URL?

116

在Java中,检查URL是否有效的最佳方法是什么?

如果尝试调用new URL(urlString)并捕获MalformedURLException,但它似乎会接受任何以http://开头的内容。

我不关心建立连接,只关心有效性。有没有这方面的方法?Hibernate验证器中的注释?我应该使用正则表达式吗?

编辑:一些被接受的URL示例是http://***http://my favorite site!


1
如果您不打算建立连接,那么如何定义有效性? - Michael Myers
2
你能给一个在 URL 构造函数中被接受但不是有效的 URL 的例子吗? - uckelman
2
@mmyers:有效性应该由RFC 2396和2732确定,它们定义了什么是URL。 - uckelman
4
几乎任何东西都可以。 "http://***" 可以使用。 "http://我最喜欢的网站!" 也可以使用。但我无法让它抛出异常(当http://在开头时)。 - Eric Wilson
2
可能是Java中验证URL的重复问题 - JasonB
显示剩余2条评论
9个回答

115

考虑使用 Apache Commons UrlValidator 类

UrlValidator urlValidator = new UrlValidator();
urlValidator.isValid("http://my favorite site!");

有几个属性可以设置来控制这个类的行为,默认情况下接受httphttpsftp


8
似乎它不能与较新的域名(例如.london等)配合使用。 - V H
内网网址怎么样? - Puneet
它不会验证带有下划线的URL。 - Udit Kumawat
无法与新的顶级域名和本地域名一起使用,例如 local 等。 - user9461715
我无法让 UrlValidator 与我们奇怪的内部顶级域名一起使用。像 .com、.org 这样的常见域名是可以使用的。我不想为此创建一个 RegExp,所以 new URL(name).toURI() 成为了解决方案。 - Avec
这会在像“é”这样的字符上返回false。我知道,对于英语人士来说,你可能不在意。但是有很多类似的字符存在,如果你想构建一个国际化的东西,你应该记住这一点。 - Netsab612

69

这是我尝试过的一种有用的方法,

URL u = new URL(name); // this would check for the protocol
u.toURI(); // does the extra checking required for validation of URI 

2
不错。只使用 new URL(name) 就可以接受几乎所有内容。url.toURI() 正是开发人员所寻找的 - 而无需使用其他库/框架! - justastefan
2
这也无法处理格式不正确的URL,例如http:/google.com。我使用了Apache Commons中的UrlValidator。 - starf
2
这个很危险。我看到有很多其他的文章都有这个例子。URL u = new URL(http://google).toURI();不会抛出异常。 - Sonu Oommen
4
也许是因为 new URL(http://google) 是合法的^^ 我们公司有很多像这样的内部域名 - user43968

8
我很想把这个作为评论发表在Tendayi Mawushe的回答下面,但是我担心没有足够的空间;)
这是Apache Commons UrlValidator 源代码中相关的部分:
/**
 * This expression derived/taken from the BNF for URI (RFC2396).
 */
private static final String URL_PATTERN =
        "/^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?/";
//         12            3  4          5       6   7        8 9

/**
 * Schema/Protocol (ie. http:, ftp:, file:, etc).
 */
private static final int PARSE_URL_SCHEME = 2;

/**
 * Includes hostname/ip and port number.
 */
private static final int PARSE_URL_AUTHORITY = 4;

private static final int PARSE_URL_PATH = 5;

private static final int PARSE_URL_QUERY = 7;

private static final int PARSE_URL_FRAGMENT = 9;

您可以轻松地从那里构建自己的验证器。


7
最“傻瓜式”的方法是检查URL的可用性:
public boolean isURL(String url) {
  try {
     (new java.net.URL(url)).openStream().close();
     return true;
  } catch (Exception ex) { }
  return false;
}

3
实际查询URL可能会导致更改、操作或跟踪。 OP希望在不进行查询的情况下检查有效性。例如,也许这是为了现在存储并稍后执行,以合理保证其有效性。 - Eric G

5

我最喜欢的方法是不使用外部库:

try {
    URI uri = new URI(name);

    // perform checks for scheme, authority, host, etc., based on your requirements

    if ("mailto".equals(uri.getScheme()) {/*Code*/}
    if (uri.getHost() == null) {/*Code*/}

} catch (URISyntaxException e) {
}

4
我不喜欢任何一种实现方式(因为它们使用正则表达式,这是一种昂贵的操作,或者使用一个库,如果你只需要一个方法,这种方式有些过度),所以我最终使用了java.net.URI类,并添加了一些额外的检查,并限制协议:http、https、file、ftp、mailto、news、urn。
是的,捕获异常可能是一种昂贵的操作,但可能没有正则表达式那么糟糕。
final static Set<String> protocols, protocolsWithHost;

static {
  protocolsWithHost = new HashSet<String>( 
      Arrays.asList( new String[]{ "file", "ftp", "http", "https" } ) 
  );
  protocols = new HashSet<String>( 
      Arrays.asList( new String[]{ "mailto", "news", "urn" } ) 
  );
  protocols.addAll(protocolsWithHost);
}

public static boolean isURI(String str) {
  int colon = str.indexOf(':');
  if (colon < 3)                      return false;

  String proto = str.substring(0, colon).toLowerCase();
  if (!protocols.contains(proto))     return false;

  try {
    URI uri = new URI(str);
    if (protocolsWithHost.contains(proto)) {
      if (uri.getHost() == null)      return false;

      String path = uri.getPath();
      if (path != null) {
        for (int i=path.length()-1; i >= 0; i--) {
          if ("?<>:*|\"".indexOf( path.charAt(i) ) > -1)
            return false;
        }
      }
    }

    return true;
  } catch ( Exception ex ) {}

  return false;
}

3
根据URI的源代码,可以判断
public URL(URL context, String spec, URLStreamHandler handler)

constructor比其他构造函数执行更多的验证。你可以尝试使用它,但效果可能因人而异。


2

验证器包:

似乎有一个由Yonatan Matalon创建的UrlUtil包。引用其API:

isValidWebPageAddress(java.lang.String address, boolean validateSyntax, 
                      boolean validateExistance) 
Checks if the given address is a valid web page address.

太阳公司的方法 - 检查网络地址
太阳公司的Java网站提供了一个连接尝试作为解决方案来验证URL。
其他正则表达式代码片段: Oracle的网站weberdev.com上有正则表达式验证尝试。

2
该代码用于检查链接,这是一个不同的问题。这个问题是关于URL的有效性,而不是是否可以连接到它。 - Michael Myers
1
此示例是关于检查URL是否可用,而不是它是否格式良好。 - uckelman
同意,添加了其他方法。 - Adam Matan

0

在 org.apache.xerces.util.URI 中也有一个函数。

isWellFormedAddress(java.lang.String address)

确定一个字符串是否在语法上能够表示有效的IPv4地址、IPv6引用或网络主机的域名。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接