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¶m2=" |
首先,我尝试构建如下的URL字符串:
1 | Sting urlString = protocol+host+location |
URL类的构造函数不转义空格和双引号:
1 |
URI类的构造函数失败,出现异常:
1 | new URI(urlString) |
然后我发现uri可以转义查询字符串中的参数,但只有很少的构造函数,例如:
1 2 | URI uri = new URI("http","example.com", "/path/path","param1=param1Data¶m2= "", 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 |
一个更好的方法,也可以处理碎片可以是:
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¶m2=otherValue"); URL url = uri.toURL(); |