在Java中确定字符串是绝对URL还是相对URL

29

给定一个字符串,如何在Java中确定它是绝对URL还是相对URL? 我尝试了以下代码:

private boolean isAbsoluteURL(String urlString) {
    boolean result = false;
    try
    {
        URL url = new URL(urlString);
        String protocol = url.getProtocol();
        if (protocol != null && protocol.trim().length() > 0)
            result = true;
    }
    catch (MalformedURLException e)
    {
        return false;
    }
    return result;
}
问 题 是 所有 相对 URL(www.google.com/questions/ask)都会 抛出 MalformedURLException,因为没有 定义 协议。

2
因此,您捕获异常并返回false,表示相对URL实际上不是绝对URL,这是预期的结果。那么问题在哪里? - Karl Knechtel
请注意,URL使用您的网络连接。 - OscarRyz
4
对于 file: 协议而言,/ 是一个绝对 URL,但是对于 http: 协议而言,/ 是一个相对 URL。如果你不知道基础 URL(实际上是协议),你无法确定给定 URL 的相对性。在你的例子中,www.google.com 是一个相对 URL,所以你的方法在这种情况下是正确的且符合规范,但它并不能解决你的问题。 - khachik
4个回答

52
这样行吗:
final URI u = new URI("http://www.anigota.com/start");
// URI u = new URI("/works/with/me/too");
// URI u = new URI("/can/../do/./more/../sophis?ticated=stuff+too");

if (u.isAbsolute())
{
  System.out.println("Yes, I am absolute!");
}
else
{
  System.out.println("Ohh noes, it's a relative URI!");
}

更多信息在此处


6
似乎这个功能不支持协议相对URL(像//这样的URL)。你可以在IDEOne上试一下 - Brad Parks
可以使用它来执行绝对重定向,就像这个例子 - Brad Parks
请注意,您仍然需要处理一个异常:URISyntaxException。这似乎并不困扰 OP,但在我的情况下,我更喜欢一个真正的一行代码解决方案。 - user1075613
1
URI.create - Abhijit Sarkar
@Abhijit Sarkar,你应该把这个发表为答案(否则我会发表的 :p),我会投票支持你! - user1075613
@user1075613 这并不是一个独立的答案,因为原帖并没有询问如何在不抛出已检查异常的情况下创建 URI。如果你只回答这个问题,很可能会被我等人投票否决。 - Abhijit Sarkar

4

正如我在我的评论中所说,您必须在检查URL之前对其进行规范化,并且该规范化取决于您的应用程序,因为www.google.com不是绝对URL。这里有一个示例代码,可用于检查URL是否为绝对URL:

import java.net.URL;

public class Test {
  public static void main(String [] args) throws Exception {
    String [] urls = {"www.google.com",
                      "http://www.google.com",
                      "/search",
                      "file:/dir/file",
                      "file://localhost/dir/file",
                      "file:///dir/file"};
    
    for (String url : urls) {
      System.out.println("`" + url + "' is " + 
                          (isAbsoluteURL(url)?"absolute":"relative"));
    }
  }

  public static boolean isAbsoluteURL(String url)
                          throws java.net.MalformedURLException {
    final URL baseHTTP = new URL("http://example.com");
    final URL baseFILE = new URL("file:///");
    URL frelative = new URL(baseFILE, url);
    URL hrelative = new URL(baseHTTP, url);
    System.err.println("DEBUG: file URL: " + frelative.toString());
    System.err.println("DEBUG: http URL: " + hrelative.toString());
    return frelative.equals(hrelative);
  }
}

输出:

~$ java Test 2>/dev/null
`www.google.com' is relative
`http://www.google.com' is absolute
`/search' is relative
`file:/dir/file' is absolute
`file://localhost/dir/file' is absolute
`file:///dir/file' is absolute

2

这是我用来确保链接为绝对路径的代码片段:

private String ensureAbsoluteURL(String base, String maybeRelative) {
    if (maybeRelative.startsWith("http")) {
        return maybeRelative;
    } else {
        try {
           return new URL(new URL(base), maybeRelative).toExternalForm();
        } catch (MalformedURLException e) {
           // do something
        }
    }
}

1
这不是正确的解决方案。http/foo.html 是一个相对 URL,指向 html 子目录,但您的代码会认为它是绝对的。 - Stephen Ostermiller
你的解决方案会是什么样子,@StephenOstermiller? - Renaud
1
这里的其他答案使用了 URL.isAbsolute(),我认为那是一个不错的解决方案。 - Stephen Ostermiller

1
我做了这个:

public static String processUrl(String urlToProcess, String grantedNormalUrl){
    if (urlToProcess.startsWith("//")){
        urlToProcess = checkUrlStartsWithProtocol(urlToProcess);
        return urlToProcess;
    }

    if (!isAbsolute(urlToProcess)){
        String rootPage = extractRootPage(grantedNormalUrl);
        boolean domainEndsWithSlash = rootPage.endsWith("/");
        boolean urlStartsWithSlash = urlToProcess.startsWith("/");
        if (domainEndsWithSlash && urlStartsWithSlash){
            rootPage = rootPage.substring(0, rootPage.length() - 1); // exclude /
        }
        urlToProcess = rootPage + (!(domainEndsWithSlash || urlStartsWithSlash) ? "/" : "") + urlToProcess;
    }

    return urlToProcess;
}

public static boolean isAbsolute(String url){
    if (url.startsWith("//")) { // //www.domain.com/start
        return true;
    }

    if (url.startsWith("/")){ // /somePage.html
        return false;
    }

    boolean result = false;

    try {
        URI uri = new URI(url);
        result = uri.isAbsolute();
    } catch (URISyntaxException e) {
        e.printStackTrace();
    }

    return result;
}

public static String checkUrlStartsWithProtocol(String url) {
    if (!url.startsWith("http://") && !url.startsWith("https://")) {
        StringBuilder prefixBuilder = new StringBuilder();
        prefixBuilder.append("http:");
        if (!url.startsWith("//")) {
            prefixBuilder.append("//");
        }
        url = prefixBuilder.toString() + url;
    }
    return url;
}

public static String extractRootPage(String urlString) {
    int ignoreSlashes = 0;
    if (urlString.startsWith("http://") || urlString.startsWith("https://")) {
        ignoreSlashes = 2;
    }
    int endPosition = urlString.length();
    for (int i = 0; i < urlString.length(); i++) {
        if (urlString.charAt(i) == '/') {
            if (ignoreSlashes == 0) {
                endPosition = i; // substring exclude /
                break;
            } else {
                ignoreSlashes--;
            }
        }
    }
    return checkUrlStartsWithProtocol(urlString.substring(0, endPosition));
}

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