假设我有一个指向 http://example.com/myItems
或者 http://example.com/myItems/
的java.net.URL对象,是否有某种助手方法可以将一些相对URL添加到它的末尾?例如添加 ./myItemId
或 myItemId
以获取: http://example.com/myItems/myItemId
。
假设我有一个指向 http://example.com/myItems
或者 http://example.com/myItems/
的java.net.URL对象,是否有某种助手方法可以将一些相对URL添加到它的末尾?例如添加 ./myItemId
或 myItemId
以获取: http://example.com/myItems/myItemId
。
URL
有一个constructor,它需要一个基本的URL
和一个String
规范。
或者,java.net.URI
更加符合标准,并且有一个resolve
方法来完成相同的操作。使用URL.toURI
从你的URL
创建一个URI
。
这个不需要任何额外的库或代码,就可以得到所需的结果:
//import java.net.URL;
URL url1 = new URL("http://petstore.swagger.wordnik.com/api/api-docs?foo=1&bar=baz");
URL url2 = new URL(url1.getProtocol(), url1.getHost(), url1.getPort(), url1.getPath() + "/pet" + "?" + url1.getQuery(), null);
System.out.println(url1);
System.out.println(url2);
这将打印:
http://petstore.swagger.wordnik.com/api/api-docs?foo=1&bar=baz
http://petstore.swagger.wordnik.com/api/api-docs/pet?foo=1&bar=baz
在主机名后面没有路径时,才能使用被接受的答案(我认为被接受的答案是错误的)。
url1.getFile().endsWith("/") ? url1.getFile() + "pet" : url1.getFile() + "/pet"
?请注意,这是一段编程相关的内容,翻译时需要保留其专业性和准确性。 - Christoph Henkelmann你可以使用 URI
类来实现这个功能:
import java.net.URI;
import org.apache.http.client.utils.URIBuilder;
URI uri = URI.create("http://example.com/basepath/");
URI uri2 = uri.resolve("./relative");
// => http://example.com/basepath/relative
请注意基本路径的末尾斜线和正在附加的段的基于基本路径的格式。您还可以使用Apache HTTP客户端的URIBuilder
类:
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.3</version>
</dependency>
...
import java.net.URI;
import org.apache.http.client.utils.URIBuilder;
URI uri = URI.create("http://example.com/basepath");
URI uri2 = appendPath(uri, "relative");
// => http://example.com/basepath/relative
public URI appendPath(URI uri, String path) {
URIBuilder builder = new URIBuilder(uri);
builder.setPath(URI.create(builder.getPath() + "/").resolve("./" + path).getPath());
return builder.build();
}
http://example.com/basepath/relative
,而是http://example.com/relative
,很遗憾这使得我之前回答的第一部分是错误的。 - Luciano我简直不敢相信 URI.resolve()
有多糟糕,它充满了许多恶心的边角情况。
new URI("http://localhost:80").resolve("foo") => "http://localhost:80foo"
new URI("http://localhost:80").resolve("//foo") => "http://foo"
new URI("http://localhost:80").resolve(".//foo") => "http://foo"
我见过的处理这些边缘情况最为整洁且可预测的解决方案是:
URI addPath(URI uri, String path) {
String newPath;
if (path.startsWith("/")) newPath = path.replaceAll("//+", "/");
else if (uri.getPath().endsWith("/")) newPath = uri.getPath() + path.replaceAll("//+", "/");
else newPath = uri.getPath() + "/" + path.replaceAll("//+", "/");
return uri.resolve(newPath).normalize();
}
结果:
jshell> addPath(new URI("http://localhost"), "sub/path")
$3 ==> http://localhost/sub/path
jshell> addPath(new URI("http://localhost/"), "sub/path")
$4 ==> http://localhost/sub/path
jshell> addPath(new URI("http://localhost/"), "/sub/path")
$5 ==> http://localhost/sub/path
jshell> addPath(new URI("http://localhost/random-path"), "/sub/path")
$6 ==> http://localhost/sub/path
jshell> addPath(new URI("http://localhost/random-path"), "./sub/path")
$7 ==> http://localhost/random-path/sub/path
jshell> addPath(new URI("http://localhost/random-path"), "../sub/path")
$8 ==> http://localhost/sub/path
jshell> addPath(new URI("http://localhost"), "../sub/path")
$9 ==> http://localhost/../sub/path
jshell> addPath(new URI("http://localhost/"), "//sub/path")
$10 ==> http://localhost/sub/path
jshell> addPath(new URI("http://localhost/"), "//sub/./path")
$11 ==> http://localhost/sub/path
URI.resolve
函数在前面加上双斜杠的结果是正确的,这被称为“协议相对 URL”,曾经很常见,但现在不再鼓励使用。请参见 维基百科。如果第二个参数始终是路径,则您的 addPath
函数是正确的,但是 URI.resolve
处理更一般的情况,其中第二个参数可能是完整的 URL。 - Kyle Pittman这是我编写的一个辅助函数,用于添加到URL路径中:
public static URL concatenate(URL baseUrl, String extraPath) throws URISyntaxException,
MalformedURLException {
URI uri = baseUrl.toURI();
String newPath = uri.getPath() + '/' + extraPath;
URI newUri = uri.resolve(newPath);
return newUri.toURL();
}
baseUrl
以 /
结尾或 extraPath
以 /
开始,则最终的 URL 中会出现重复的 /
。在最后一个 toURL()
前应该添加 .normalize()
。 - Simão MartinsbaseUrl.getPath()
是"/"
,这将修改主机!URI("http://localhost:80").resolve("//foo")
=> "http://foo"
我将在下面展示如何解决这些问题。 - iainURI#normalize
来避免URI中重复出现的/
。URIBuilder uriBuilder = new URIBuilder("http://example.com/test");
URI uri = uriBuilder.setPath(uriBuilder.getPath() + "/path/to/add")
.build()
.normalize();
// expected : http://example.com/test/path/to/add
private String appendSegmentToPath(String path, String segment) {
if (path == null || path.isEmpty()) {
return "/" + segment;
}
if (path.charAt(path.length() - 1) == '/') {
return path + segment;
}
return path + "/" + segment;
}
这里是我找到的源代码。
结合Apache URIBuilder,这是我使用的方式:builder.setPath(appendSegmentToPath(builder.getPath(), segment));
将相对路径连接到URI:
java.net.URI uri = URI.create("https://stackoverflow.com/questions")
java.net.URI res = uri.resolve(uri.getPath + "/some/path")
res
将包含https://stackoverflow.com/questions/some/path
uri.getPath
替代,谢谢! - Martin Tapp更新
我相信这是最简单的解决方案:
URL url1 = new URL("http://domain.com/contextpath");
String relativePath = "/additional/relative/path";
URL concatenatedUrl = new URL(url1.toExternalForm() + relativePath);
new URL("/additional/relative/path");
抛出 MalformedURLException。 - Konstantin Pelepelinimport java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
class URLHelper {
public static URL appendRelativePathToURL(URL base, String relPath) {
/*
foo://example.com:8042/over/there?name=ferret#nose
\_/ \______________/\_________/ \_________/ \__/
| | | | |
scheme authority path query fragment
| _____________________|__
/ \ / \
urn:example:animal:ferret:nose
see https://en.wikipedia.org/wiki/Uniform_Resource_Identifier
*/
try {
URI baseUri = base.toURI();
// cut initial slash of relative path
String relPathToAdd = relPath.startsWith("/") ? relPath.substring(1) : relPath;
// cut trailing slash of present path
String path = baseUri.getPath();
String pathWithoutTrailingSlash = path.endsWith("/") ? path.substring(0, path.length() - 1) : path;
return new URI(baseUri.getScheme(),
baseUri.getAuthority(),
pathWithoutTrailingSlash + "/" + relPathToAdd,
baseUri.getQuery(),
baseUri.getFragment()).toURL();
} catch (URISyntaxException e) {
throw new MalformedURLRuntimeException("Error parsing URI.", e);
} catch (MalformedURLException e) {
throw new MalformedURLRuntimeException("Malformed URL.", e);
}
}
public static class MalformedURLRuntimeException extends RuntimeException {
public MalformedURLRuntimeException(String msg, Throwable cause) {
super("Malformed URL: " + msg, cause);
}
}
}
private void demo() {
try {
URL coolURL = new URL("http://fun.de/path/a/b/c?query&another=3#asdf");
URL notSoCoolURL = new URL("http://fun.de/path/a/b/c/?query&another=3#asdf");
System.out.println(URLHelper.appendRelativePathToURL(coolURL, "d"));
System.out.println(URLHelper.appendRelativePathToURL(coolURL, "/d"));
System.out.println(URLHelper.appendRelativePathToURL(notSoCoolURL, "d"));
System.out.println(URLHelper.appendRelativePathToURL(notSoCoolURL, "/d"));
} catch (MalformedURLException e) {
e.printStackTrace();
}
}