0

我想解析一些网址。为此,我采用以下结果:

  new URL(new URL(baseurl), link);

这种方法似乎在何时baseurl="http://www.site.com"失败link="./"

您将得到以下结果http://www.site.com/./,而不仅仅是http://www.site.com/

我该如何解决这个问题?

4

4 回答 4

1

使用URI.normalize().

import java.net.*;

class TestURL {

    public static void main(String[] args) throws Exception {
        String s = "http://www.site.com/./";
        URL url = new URL(s);
        System.out.println(url);
        URI uri = url.toURI();
        System.out.println(uri.normalize().toURL());
    }
}

输出

http://www.site.com/./
http://www.site.com/
于 2013-04-13T23:28:49.317 回答
1

也许这会起作用?

new URI(baseUrl).resolve(link).toURL()

java.net.URI有一个 resolve 方法,它可能是您正在寻找的方法和 toURL 以将其放入 URL 。

编辑

以下似乎对我有用..

import java.net.URL;


public class UrlTest {

    private static URL resolve(URL base, String link) throws Exception {
        if (base.getPath().isEmpty()) {
            link = "/" + link;
        }       
        URL u1 = base.toURI().resolve(link).normalize().toURL();
        return u1;
    }

    private static void resolveUrls(URL baseUrl) throws Exception {
        String link = "abcd";
        String link2 = "./";
        String link3 = "./foo";
        System.out.println(resolve(baseUrl, link));
        System.out.println(resolve(baseUrl, link2));
        System.out.println(resolve(baseUrl, link3));
    }

    public static void main(String[] args) throws Exception {   
        String baseUrlStr = "http://www.somesite.com";
        URL baseUrl = new URL(baseUrlStr);
        resolveUrls(baseUrl);
        baseUrl = new URL(baseUrlStr + "/index.html");
        resolveUrls(baseUrl);
        baseUrl = new URL(baseUrlStr + "/path/index.html");
        resolveUrls(baseUrl);
    }

}
于 2013-04-13T21:56:14.710 回答
1

你可以试试这个

new URL(new URL(baseurl), link.replace("./"), "");
于 2013-04-13T21:56:56.453 回答
1

这是一个很长的帖子,虽然内容丰富,但在很大程度上没有帮助,但实际上最后有一个答案。

这都是一个有点悲伤的故事。这显然是完全疯狂的:

URI base = new URI("http", "example.org", null, null);
URI link = new URI(null, null, "index.html", null);
System.out.println(base.resolve(link));

应该打印:

http://example.orgindex.html

而不是:

http://example.org/index.html

然而它确实如此。为什么?因为java.net.URI...

表示由RFC 2396定义的 URI 引用:统一资源标识符 (URI):通用语法

并且忠实地这样做。特别是,该resolve方法...

以符合 RFC 2396第 5.2 节的方式构造新的分层 URI

遗憾的是,第 5.2 节中指定的算法是错误的。具体来说,虽然它说...

路径组件永远不会未定义,尽管它可能为空

它不能确保针对具有空路径的基本 URI 解析相对 URI 的结果是有效的 URI。问题出在第 6 步,它处理将来自基本 URI 和相对 URI 的路径合并到一个缓冲区中,该缓冲区将用于形成解析的 URI。步骤 6 的前两个子步骤是:

a) 除了基 URI 的路径组件的最后一段之外的所有部分都被复制到缓冲区。换句话说,最后一个(最右边的)斜线字符之后的任何字符(如果有)都将被排除。

b) 引用的路径组件附加到缓冲区字符串。

如果基础 URI 的路径为空,则在子步骤 a 之后,缓冲区将为空。如果相对 URI 有一个不以 / 开头的路径,那么在子步骤 b 之后,缓冲区将包含一个不以 / 开头的字符串。以下步骤处理点规范化,并且不添加前导 /。最后一步是:

h) 剩余的缓冲区字符串是引用 URI 的新路径组件。

因此,解析的 URI 有一个不以 / 开头的路径。然后,第 7 步将其构建为已解析 URI 的最终字符串形式,而无需任何插入 / 的规定。因此,将没有前导 / 的相对 URI 解析为具有空路径的基本 URI 会导致胡说八道。这是 RFC 2396 指定的内容,也是java.net.URI如此。

哎呀!

故事并没有就此结束。2005 年 1 月,发布了RFC 3986。此已过时的 RFC 2396,并在第 5.2 节中再次包含 URI 解析的新定义。这个定义以更严格(或至少看起来很严谨)的风格完全重写,并在5.2.3 节中指定了路径的合并,首先要做到这一点:

如果基本 URI 具有已定义的权限组件和空路径,则返回由“/”与引用路径连接的字符串

因此,如果更新 Java 以符合 8 年前的 RFC,而不是 14 年前的 RFC,整个问题就会得到解决。这样做是错误 6791060中所要求的,该错误于 2009 年开放,最后一次触及是在 2010 年。孙,我很失望。

无论如何,有了这种理解,我们可以看到正确的解决方案是:

public static URI fix(URI uri) {
    if (uri.getPath().isEmpty()) {
        try {
            return new URI(uri.getScheme(), uri.getAuthority(), "/", uri.getQuery(), uri.getFragment());
        }
        catch (URISyntaxException e) {
            AssertionError ae = new AssertionError("highly implausible error fixing URI " + uri);
            ae.initCause(e);
            throw ae;
        }
    }
    else {
        return uri;
    }
}

fix(new URI(baseurl)).resolve(link);
于 2013-04-14T01:09:17.393 回答