关于http:如何使用Java从相对URL构建绝对URL?

How to build an absolute URL from a relative URL using Java?

我有一个相对的URL字符串,知道主机和协议。如何构建绝对URL字符串?

似乎很容易?是的,第一眼看,但直到逃犯来了。我必须从302代码HTTP(S)响应位置头构建绝对URL。

让我们考虑一个例子

1
2
3
protocol: http
host: example.com
location: /path/path?param1=param1Data&param2="

首先,我尝试构建如下的URL字符串:

1
Sting urlString = protocol+host+location

URL类的构造函数不转义空格和双引号:

1
new URL(urlString)

URI类的构造函数失败,出现异常:

1
new URI(urlString)

URI.resolve方法也失败了,除了

然后我发现uri可以转义查询字符串中的参数,但只有很少的构造函数,例如:

1
2
URI uri = new URI("http","example.com",
   "/path/path","param1=param1Data&param2= "", null);

这个构造函数需要path和query是一个单独的参数,但是我有一个相对的url,它不按path和query部分拆分。

我可以考虑检查相对URL是否包含"?"问号并认为它之前的一切都是路径,之后的一切都是查询,但是如果相对URL不包含路径,而只包含查询,而查询包含"?"标志?那么这将不起作用,因为查询的一部分将被视为路径。

现在我无法从相对URL中获得如何构建绝对URL。

这些公认的答案似乎是错误的:

  • 如何使用相对路径获取URL
  • 将相对URL附加到java.net.url
  • 从Java中的相对URL构建绝对URL

当给出了与主机和某些路径部分的URL相关的相对URL时,最好考虑一下场景:

初始URL http://example.com/…某些路径…亲戚/家?…在此查询…

如果可以使用一个好的LIB,那么可以获得Java核心解决方案。


第一个?指示查询字符串的起始位置:

3.4. Query

[...] The query component is indicated by the first question mark (?) character and terminated by a number sign (#) character or by the end of the URI.

一个简单的方法(不处理片段并假定查询字符串始终存在)简单如下:

1
2
3
4
5
6
7
8
String protocol ="http";
String host ="example.com";
String location ="/path/path?key1=value1&key2=value2";

String path = location.substring(0, location.indexOf("?"));
String query = location.substring(location.indexOf("?") + 1);

URI uri = new URI(protocol, host, path, query, null);

一个更好的方法,也可以处理碎片可以是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
String protocol ="http";
String host ="example.com";
String location ="/path/path?key1=value1&key2=value2#fragment";

// Split the location without removing the delimiters
String[] parts = location.split("(?=\\?)|(?=#)");

String path = null;
String query = null;
String fragment = null;

// Iterate over the parts to find path, query and fragment
for (String part : parts) {

    // The query string starts with ?
    if (part.startsWith("?")) {
        query = part.substring(1);
        continue;
    }

    // The fragment starts with #
    if (part.startsWith("#")) {
        fragment = part.substring(1);
        continue;
    }

    // Path is what's left
    path = part;
}

URI uri = new URI(protocol, host, path, query, fragment);


最好的方法似乎是使用多段构造函数创建一个URI对象,然后将其转换为类似这样的URL:

1
2
URI uri = new URI("https","sitename.domain.tld","/path/goes/here","param1=value&param2=otherValue");
URL url = uri.toURL();