在 Java 中编写 URL 或 URI 的惯用方式是啥?

Posted

技术标签:

【中文标题】在 Java 中编写 URL 或 URI 的惯用方式是啥?【英文标题】:What is the idiomatic way to compose a URL or URI in Java?在 Java 中编写 URL 或 URI 的惯用方式是什么? 【发布时间】:2010-10-27 08:33:21 【问题描述】:

如何在 Java 中构建 URL 或 URI?有没有一种惯用的方式或库可以轻松做到这一点?

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

【问题讨论】:

在该问题关闭很久后对其进行投票,因为尚不清楚是否存在针对此问题的流行且不弃用的解决方案。我通过谷歌搜索“java URL 参数类”找到了这一点。 我的目的是为 Java 找到一个 URL 构建器,这个问题至少对我有用。 【参考方案1】:

截至Apache HTTP Component HttpClient 4.1.3,来自官方tutorial:

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=


编辑:从 v4.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());

【讨论】:

这可行,但从 v4.2 开始,URIUtils.createURI() 已被弃用,取而代之的是 URIBuilder。从积极的方面来说,这个 URIBuilder 似乎有一个 addParameter() 方法,所以现在构建请求字符串应该更简单了。 URIBuilder builder = new URIBuilder() .setScheme("http") .setHost("www.google.com") .setParameters(qparams); 正如@stian所说的 Println 上面打印以下内容; google.com/… 教程链接失效 要给出多条路径时如何设置路径?例如。 "localhost/api/customer" + "/" +Id1 + "/" + "summary?invoiceId=" + Id2 + "&page=0&pageSize=10&q=" + Id3;【参考方案2】:

作为作者,我可能不是判断我的 URL/URI 构建器是否的最佳人选,但这里仍然是:https://github.com/mikaelhg/urlbuilder

我想要最简单的完整解决方案,在 JDK 之外零依赖,所以我不得不自己动手。

【讨论】:

它看起来很棒 Mikael,你有没有想过将它发布到 maven Central?我知道它很小,但使用起来更容易。除了在 JAX-RS 中,我找不到类似的课程。缺乏依赖绝对是一个加分项。 看起来不错,但既然它是一个构建器,因此是可变的,为什么只有参数的设置器,而不是主机、端口、协议和路径的设置器?而且,好吧,那些也没有吸气剂。 UPD:哦,它不是可变的 - setParameter 创建一个克隆。好吧,仍然 setHost/setPort/... 可以以相同的方式工作。或者,也许,一个可变版本也很不错。 “零依赖的最简单的完整解决方案” - 听起来你知道什么是重要的!您的答案应该是公认的恕我直言。包括所有的 HttpClient(包括它的所有版本更新,甚至弃用这个问题所涉及的 API)只是为了构建一个 url 是导致头重脚轻的 bug 困扰的应用程序的原因。 终于在 Maven Central 上,我只花了四年时间就完成了。 @mikaelhg 谢谢!我正是在这一刻需要!【参考方案3】:

Apache HTTPClient?

【讨论】:

截至 2015 年 6 月:hc.apache.org/httpcomponents-client-ga/tutorial/html/…【参考方案4】:

使用 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();


【讨论】:

现在已弃用此功能。有谁知道如何使用新的 HTTP 组件包来做同样的事情,因为它难倒我。 新的4x版本不再支持这个了。【参考方案5】:

有很多库可以帮助您构建 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

【讨论】:

EE 7 是正确答案。您所要做的就是引入整套 EE 库,选择一个 JAX-RS 实现,解决 jax-rs 版本冲突,作为奖励,您将拥有一个运行良好的方便的 UriBuilder 类。撇开讽刺不谈,这正确答案。 :) 从 Spring 5 开始,请查看 UriBuilder (docs.spring.io/spring-framework/docs/current/javadoc-api/org/…) 和 UriBuilderFactory (docs.spring.io/spring-framework/docs/current/javadoc-api/org/…)【参考方案6】:

使用 OkHttp

现在是 2021,有一个非常受欢迎的库,名为 OkHttp,它在 GitHub 上已被加星标 40K 次。使用这个库,您可以构建一个如下所示的 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 都因不同的原因而存在,已恢复修复。【参考方案7】:

在因建议 URL 类而受到抨击之后。我会采纳评论者的建议并建议使用URI class。我建议您仔细查看 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.

【讨论】:

但它不提供从一组名称值对中实际构造和编码查询字符串的功能。 正如神童对艾伦·帕特里奇所说的那样——不变性不能退化,要么是,要么不是;-) youtube.com/watch?v=_lvFns5Lubc URI 的构造函数对路径做了一些讨厌的事情。详情请见blog.palominolabs.com/2013/10/03/…。 让这个答案作为一个例子来说明如何不这样做。 字符串查询...感谢 Sun/Oracle 提供的粒度。我们将用加号替换所有空格,对所有参数进行 uri 编码,然后自己用 & 符号将它们链接在一起...... 反复敲击桌面

以上是关于在 Java 中编写 URL 或 URI 的惯用方式是啥?的主要内容,如果未能解决你的问题,请参考以下文章

java adapter(适配器)惯用方法

uri和url有啥关系和区别?

Java URL 类 getPath()、getQuery() 和 getFile() 与 RFC3986 URI 语法不一致

java URL和URI

初始化 Java 对象的 Clojure 惯用方法

转Data URL和图片,及Data URI的利弊