在Java中,组成URL或URI的惯用方式是什么?

126

我该如何在Java中构建URL或URI?是否有惯用的方式或易于实现此操作的库?

我需要能够从请求字符串开始解析/更改各种URL部分(方案、主机、路径、查询字符串)并支持添加和自动编码查询参数。


7
因为不确定是否存在流行的非淘汰解决方案来解决这个问题,所以在问题关闭后很久仍然给问题点赞。我是通过在谷歌上搜索“java URL参数类”找到这篇文章的。 - user1445967
4
我的意图是找到一个适用于Java的URL构建器,这个问题对我至少是有用的。 - whirlwin
8个回答

80

自从Apache HTTP Component HttpClient 4.1.3版本,官方教程中提到:

public class HttpClientTest {
public static void main(String[] args) throws URISyntaxException {
    List<NameValuePair> qparams = new ArrayList<NameValuePair>();
    qparams.add(new BasicNameValuePair("q", "httpclient"));
    qparams.add(new BasicNameValuePair("btnG", "Google Search"));
    qparams.add(new BasicNameValuePair("aq", "f"));
    qparams.add(new BasicNameValuePair("oq", null));
    URI uri = URIUtils.createURI("http", "www.google.com", -1, "/search",
                                 URLEncodedUtils.format(qparams, "UTF-8"), null);
    HttpGet httpget = new HttpGet(uri);
    System.out.println(httpget.getURI());
    //http://www.google.com/search?q=httpclient&btnG=Google+Search&aq=f&oq=
}
}

编辑:自版本4.2起,URIUtils.createURI()已被弃用,推荐使用URIBuilder

URI uri = new URIBuilder()
        .setScheme("http")
        .setHost("www.google.com")
        .setPath("/search")
        .setParameter("q", "httpclient")
        .setParameter("btnG", "Google Search")
        .setParameter("aq", "f")
        .setParameter("oq", "")
        .build();
HttpGet httpget = new HttpGet(uri);
System.out.println(httpget.getURI());

20
这段代码是可行的,但从v4.2开始,URIUtils.createURI()已经被废弃,推荐使用URIBuilder。好消息是,URIBuilder似乎有一个addParameter()方法,所以现在构建请求字符串应该更简单了。 - stian
6
URIBuilder builder = new URIBuilder() .setScheme("http") .setHost("www.google.com") .setParameters(qparams);,正如@stian所说。 - vanduc1102
上面的Println输出如下内容; http://www.google.com/search?q=httpclient&btnG=Google+Search&aq=f&oq= - Berkan Ercan
教程链接已损坏。 - Alex
当需要给出多个路径时,如何设置路径?例如:"https://localhost/api/customer" + "/" +{Id1} + "/" + "summary?invoiceId=" + {Id2} + "&page=0&pageSize=10&q=" + {Id3}。 - Dhruv Bhatnagar
HC v5具有相同的功能,但该类现在是httpcomponents-core库的一部分。 - Zac Thompson

65

作为作者,我可能不是评判我的URL/URI构建器是否“好”的最佳人选,但这便是它:https://github.com/mikaelhg/urlbuilder

我想要的是最简单的完整解决方案,除了JDK外没有任何依赖,所以我不得不自己动手。


6
看起来很不错 Mikael,你有考虑发布到Maven中央仓库吗?虽然它很小但可以使使用更加便捷。我在JAX-RS中找不到类似的类。缺少依赖项绝对是一个优点。 - Barry Pitman
看起来不错,但既然它是一个构建器并且可变的,为什么只有参数有setter,而主机、端口、协议和路径没有呢?而且,这些也没有getter。更新:哦,它不是可变的——setParameter创建了一个克隆。嗯,setHost/setPort/...也可以采用同样的方式。或者,也许有一个可变版本会很好。 - mvmn
3
“simplest possible complete solution with zero dependencies” - 听起来你知道什么是重要的!在我看来,你的答案应该被接受。包括所有的HttpClient(随着它的各种版本更新,甚至废弃这个问题所涉及的API),仅为了构建一个URL,会导致应用程序变得庞大而充满错误。 - Stijn de Witt
4
终于在Maven中央库上了,只用了四年时间才完成。 - Mikael Gueck
@mikaelhg 谢谢!我正好此刻需要! - Fabian Damken
我发现这个不适合我的目的,因为每当参数改变时它都会创建一个新实例。我想能够在if语句中调用builder.addParameter(),而不必将变量设置为它。在我看来,这只是丑陋的。 - CrushedPixel

56

截至2015年6月:http://hc.apache.org/httpcomponents-client-ga/tutorial/html/fundamentals.html#d5e49 - arun

29

使用 HTTPClient 运行良好。

protected static String createUrl(List<NameValuePair> pairs) throws URIException{

  HttpMethod method = new GetMethod("http://example.org");
  method.setQueryString(pairs.toArray(new NameValuePair[]{}));

  return method.getURI().getEscapedURI();

}

7
这个功能现在已经不推荐使用了。有没有人知道如何使用新的HTTP组件包来完成同样的操作,因为它让我感到困惑。 - Link19
3
新的4x版本不再支持这个。 - Joscha

18

有很多库可以帮助你构建URI(不要重复造轮子)。以下是三个库,可供您开始使用:


Java EE 7

import javax.ws.rs.core.UriBuilder;
...
return UriBuilder.fromUri(url).queryParam(key, value).build();

org.apache.httpcomponents:httpclient:4.5.2

import org.apache.http.client.utils.URIBuilder;
...
return new URIBuilder(url).addParameter(key, value).build();

org.springframework:spring-web:4.2.5.RELEASE

import org.springframework.web.util.UriComponentsBuilder;
...
return UriComponentsBuilder.fromUriString(url).queryParam(key, value).build().toUri();

另请参阅:GIST > URI Builder Tests


3
EE 7是正确的答案。你所要做的就是引入整个EE库套件,选择一个JAX-RS实现,解决jax-rs版本冲突,作为回报,你将拥有一个非常好用的UriBuilder类。开玩笑的话,这确实是正确的答案。 :) - tekHedd
1
从Spring 5开始,请查看UriBuilder(https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/util/UriBuilder.html)和`UriBuilderFactory`(https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/util/UriBuilderFactory.html)。 - Brice Roncace

15

使用 OkHttp

现在是2022年,有一款非常流行的库叫做OkHttp,已经在 GitHub 上获得了41K次点赞。使用这个库,你可以构建如下的 URL:

import okhttp3.HttpUrl;

URL url = new HttpUrl.Builder()
    .scheme("http")
    .host("example.com")
    .port(4567)
    .addPathSegments("foldername/1234")
    .addQueryParameter("abc", "xyz")
    .build().url();

我修复了一个错别字,应该是 addPathSegment(而不是 addPathSegments)。 - PapaFreud
@PapaFreud 两者存在不同的原因,已撤销修复。 - Saikat
1
如果您的项目中已经使用了OkHttp,那么这种方法并没有什么问题。但是,如果您只需要一种构建URL的方式,我会怀疑引入一个大小为770 kB的JAR文件是否是正确的选择。 - Robert Strauch
1
@RobertStrauch 我理解你的意思。但这真的取决于情况。并非所有应用程序都对大小敏感。引入一个“大” jar 文件不会使您的应用程序变得更慢。因此,“劣势”只是大小,没有其他影响。 - Tyler Liu
@TylerLiu 我同意这一点。例如,移动应用程序的上下文与某些内部的“企业”应用程序大不相同。当有疑问时,我个人更倾向于采用 https://youmightnotneed.com 的方法,尽管这会影响 JavaScript 的世界。在引入其他库或编写自己的帮助程序之前,我首先检查项目已经使用了哪些库。 - Robert Strauch

1

因为建议使用URL类而受到责备。我会采纳评论者的建议,建议使用URI类。我建议您仔细查看URI的构造函数,因为一旦创建,该类非常不可变。
我认为这个构造函数允许您设置URI中可能需要的所有内容。

URI(String scheme, String userInfo, String host, int port, String path, String query, String fragment)
          Constructs a hierarchical URI from the given components.

8
但是它并没有提供从一组名称值对构建和编码查询字符串的功能。 - Link19
4
就像那个神童对艾伦·帕特里奇说的一样,不可能有可变性的降级,它要么存在,要么不存在。;-) - Stewart
URI的构造函数对路径做了一些讨厌的事情。有关详细信息,请参见http://blog.palominolabs.com/2013/10/03/creating-urls-correctly-and-safely/。 - mpierce
1
让这个答案成为一个反例,以说明不应该这样做。 - Mike Pone
1
字符串查询... 感谢Sun/Oracle提供的细节。我们将只需用加号符号替换所有空格,对所有参数进行URI编码,然后自己使用和号符号将它们全部链接在一起... 重复地敲打桌子 - Stijn de Witt

0
你可以使用Apache HTTPComponents Core5中包含的URIBuilder类:导入org.apache.httpcomponents.core5:httpcore5:5.2.1,然后:
URI uri = new URIBuilder("http://yourapi.com/rest")
        .addParameter("count", "5")
        .addParameter("filter", "full text search")
        .build();

httpcore5没有任何依赖,但它是一个900kb的jar文件。如果大小很重要,您可以使用这个库代替:https://gitlab.com/mvysny/apache-uribuilder - 我只是从httpcore5中复制了URIBuilder并将其发布到了Maven Central;该jar文件大小为33kb。

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