Unirest-Java 官方使用文档(中文版)

版本: unirest-java-3.12.0

翻译: 白石(https://github.com/wjw465150

HTTP请求大家都比较熟悉了,无论是使用JDK自带的HttpURLConnection抑或是apache的HttpClients或者是OkHttp,都能比较轻松便捷的发送HTTP请求,区别只是在于代码量的多少了。今天主要和大家说了Unirest-Java这个基于apache HttpComponent的工具,api更为便捷、高效,能够使用较少的代码完成复杂的请求. 官网地址为:https://kong.github.io/unirest-java/,而且可以看到,除了Java的api,还提供了Python、PHP、Nodejs等不同语言的支持。顺带说一句,Unirest-Java的github地址为https://github.com/kong/unirest-java/,其另外一个很牛逼的开源产品就是微服务的API网关kong

Maven: 安装

<!-- Pull in as a traditional dependency -->
<dependency>
    <groupId>com.konghq</groupId>
    <artifactId>unirest-java</artifactId>
    <version>3.13.2</version>
</dependency>

<!-- OR as a snazzy new standalone jar with shaded dependencies -->
<dependency>
    <groupId>com.konghq</groupId>
    <artifactId>unirest-java</artifactId>
    <version>3.13.2</version>
    <classifier>standalone</classifier>
</dependency>

Gradle: 安装

// Make sure you added the mavencentral repository
repositories {
    mavenCentral()
}

// Pull in as a traditional dependency
dependencies {
    // ... Your other dependencies
    implementation 'com.konghq:unirest-java:3.13.2'
}

// OR as a snazzy new standalone
dependencies {
    // ... Your other dependencies
    implementation 'com.konghq:unirest-java:3.13.2:standalone'
}

从以前的版本升级

参见 升级指导书

更新日志

参见 Change Log 查看最近的更改。

Requests(请求)

所以你可能想知道如何使用Unirest在Java中创建请求更容易,这里是一个基本的POST请求,它将解释一切:

HttpResponse<JsonNode> response = Unirest.post("http://localhost/post")
      .header("accept", "application/json")
      .queryString("apiKey", "123")
      .field("parameter", "value")
      .field("firstname", "Gary")
      .asJson();

当’ asType '被调用时发出请求,可能的类型包括JsonStringObjectEmptyFile

路由(路径)参数

有时您想在 URL 中添加动态参数,可以通过在 URL 中添加占位符,然后使用 routeParam 函数设置路由参数来轻松实现,例如:

Unirest.get("http://localhost/{fruit}")
     .routeParam("fruit", "apple")
     .asString();

// Results in `http://localhost/apple`

占位符 {fruit} 将被替换为 apple

占位符的格式就像用花括号括起来一样简单:{custom_name}

所有参数值都将为您进行 URL 编码

默认的基础URL

您可以配置一个默认基础URL,用于所有不包含完整URL的请求。

这个配置将导致GET到 “http://homestar.com/runner”

Unirest.config().defaultBaseUrl("http://homestar.com");
    
Unirest.get("/runner").asString();

查询参数

查询字符串参数可以一个一个地建立

Unirest.get("http://localhost")
                .queryString("fruit", "apple")
                .queryString("droid", "R2D2")
                .asString();

// Results in "http://localhost?fruit=apple&droid=R2D2"

同样,所有的参数值都是url编码的。

你也可以将查询字符串作为数组和map传入:

Unirest.get("http://localhost")
        .queryString("fruit", Arrays.asList("apple", "orange"))
        .queryString(ImmutableMap.of("droid", "R2D2", "beatle", "Ringo"))
        .asString();

 // Results in "http://localhost?fruit=apple&fruit=orange&droid=R2D2&beatle=Ringo"

请求头

请求头可以通过header’方法添加。

Unirest.get("http://localhost")
            .header("Accept", "application/json")
            .header("x-custom-header", "hello")
            .asString();

Basic 认证

Unirest 提供了在需要时进行基本身份验证的快捷方式。 Unirest 处理 Base64 编码部分。 请确保您始终通过 HTTPS 执行此操作!

Unirest.get("http://localhost")
            .basicAuth("user", "password1!")
            .asString();

//this adds the header "Authorization: Basic dXNlcjpwYXNzd29yZDEh"

Body Data(消息体数据)

Entity Bodies(实体对象Bodies)

您可以轻松地将实体对象作为body发布。 这是大多数 REST 服务的默认行为。

除非你另外指定,默认的Content-Typetext/plain; charset=UTF-8

Unirest.post("http://localhost")
                .body("This is the entire body")
                .asEmpty();

您还可以发布为使用配置的 ObjectMapper 序列化的对象。 (请参阅 Object Mappers了解实现细节)。Unirest 带有一个默认映射器,它将使用流行的 Google Gson 库序列化为 json

Unirest.post("http://localhost")
            .header("Content-Type", "application/json")
            .body(new SomeUserObject("Bob"))
            .asEmpty();

// This will use Jackson to serialize the object into JSON.

JSON Patch Bodies(JSON补丁Bodies)

Unirest 完全支持 JSON 补丁请求(RFC-6902 see http://jsonpatch.com/)规范,json-patch 的默认 Content-Typeapplication/json-patch+json

Unirest.jsonPatch("http://localhost")
            .add("/fruits/-", "Apple")
            .remove("/bugs")
            .replace("/lastname", "Flintstone")
            .test("/firstname", "Fred")
            .move("/old/location", "/new/location")
            .copy("/original/location", "/new/location")
            .asJson();

将发送如下带有正文的请求

[
     {"op":"add","path":"/fruits/-","value":"Apple"},
     {"op":"remove","path":"/bugs"},
     {"op":"replace","path":"/lastname","value":"Flintstone"},
     {"op":"test","path":"/firstname","value":"Fred"},
     {"op":"move","path":"/new/location","from":"/old/location"},
     {"op":"copy","path":"/new/location","from":"/original/location"}
  ]

Basic Forms(基本表单)

可以通过简单的field调用传递基本的 http 名称值(name value) body 参数。 此类请求的Content-Type默认为application/x-www-form-urlencoded

Unirest.post("http://localhost")
       .field("fruit", "apple")
       .field("droid", "R2D2")
       .asEmpty();

  // This will post a simple name-value pair body the same as a HTML form. This looks like
  // `fruit=apple&droid=R2D2'

文件上传

您还可以在表单中发布二进制数据。 例如一个文件。

此类请求的 Content-Type 默认为 multipart/form-data

Unirest.post("http://localhost")
       .field("upload", new File("/MyFile.zip"))
       .asEmpty();

对于大文件,您可能需要使用 InputStream。 如果需要,请传递一个文件名。 我们在这里使用 FileInputStream 但它实际上可以是任何类型的 InputStream子类。

InputStream file = new FileInputStream(new File("/MyFile.zip"));

Unirest.post("http://localhost")
       .field("upload", file, "MyFile.zip")
       .asEmpty();

上传进度监控

如果您要上传大文件,您可能希望向用户提供一些时间进度条。 您可以通过提供 ProgresMonitor 来监控此进度。

Unirest.post("http://localhost")
                .field("upload", new File("/MyFile.zip"))
                .uploadMonitor((field, fileName, bytesWritten, totalBytes) -> {
                    updateProgressBarWithBytesLeft(totalBytes - bytesWritten);
                })
                .asEmpty();

异步请求

有时候,在大多数情况下,您希望应用程序是异步的而不是阻塞的,Unirest在Java中使用匿名回调或直接方法放置来支持这一点。所有请求类型也支持异步版本。

CompletableFuture<HttpResponse<JsonNode>> future = Unirest.post("http://localhost/post")
  .header("accept", "application/json")
  .field("param1", "value1")
  .field("param2", "value2")
  .asJsonAsync(response -> {
        int code = response.getStatus();
        JsonNode body = response.getBody();
    });

分页请求

有时服务提供分页请求。 这是如何完成的并没有标准化,但 Unirest 证明了一种机制,可以跟踪页面直到所有页面都被消耗掉。 您必须提供两个函数来提取下一页。 第一个是获取您想要的格式的 HttpResponse,另一个是从响应中提取 next 链接。结果是HttpResponse<T>PagedList。 分页列表有一些处理结果的方便方法。 在这里,我们得到了一个分页的 Dogs 列表,其中 next 链接位于Header中。

PagedList<Doggos> result =  Unirest.get("https://somewhere/dogs")
                .asPaged(
                        r -> r.asObject(Doggos.class),
                        r -> r.getHeaders().getFirst("nextPage")
                );

客户端证书

如果您需要使用自定义客户端证书来调用服务,您可以为 unirest 提供自定义密钥库。 您可以传递 KeyStore 对象或有效 PKCS#12 密钥库文件的路径。

Unirest.config()
  .clientCertificateStore("/path/mykeystore.p12", "password1!");

Unirest.get("https://some.custom.secured.place.com")
                .asString();

Proxies(代理)

有时您需要通过代理隧道。Unirest可以配置为这样做。注意,身份验证代理不能按每个请求进行配置,除非您想将其构建到URL本身中。

// Configure with authentication:
    Unirest.config().proxy("proxy.com", 7777, "username", "password1!");

    // or without
    Unirest.config().proxy("proxy.com", 7777);

    // or pass it in the request. This will override any proxy done in the config
    // currently only unauthenticated proxies work
    Unirest.get(MockServer.GET)
                    .proxy("proxy.com", 7777)
                    .asString();

Responses(响应)

Unirest 在您调用它的 as[type] 方法时发出实际请求。 这些方法还通知 Unirest 将响应映射到什么类型。 选项有EmptyStringFileObjectbyteJson

响应返回一个HttpResponse<T>,其中HttpResponse对象拥有所有常见的响应数据,如状态和头信息。可以通过.getbody()方法访问Body(如果存在)。

Empty Responses(空响应)

如果你不关心响应回来的消息体,asEmpty 是最简单的选择。 您仍然会得到状态和标题等响应信息。

HttpResponse response = Unirest.delete("http://localhost").asEmpty()

String Responses(字符串响应)

下一个最简单的响应类型是String。你想怎么处理都可以。

String body = Unirest.get("http://localhost")
					 .asString()
					 .getBody();

Object Mapped Responses(对象映射响应)

大多数情况下,在使用 RESTful 服务时,您可能希望将响应映射到一个对象中。

为此,您需要为 Unirest 配置提供“ObjectMapper”的实现(有关详细信息,请参阅 Object Mappers)。

如果响应是 JSON,那么你很幸运,Unirest 在 Google GSON 上提供了一个基本的JsonObjectMapper

asObject(Class) 之前,有必要提供 ObjectMapper 接口的自定义实现(如果您不想使用默认映射器)。 这应该只在第一次完成,因为 ObjectMapper 的实例将被全局共享。

Unirest 提供了一些插件来实现流行的对象映射器,如 Jackson 和 Gson。 详情请参阅 mvn central

例如,

// Response to Object
Book book = Unirest.get("http://localhost/books/1")
                   .asObject(Book.class)
                   .getBody();

// Generic types can be resolved by using a GenericType subclass to avoid erasure
List<Book> books = Unirest.get("http://localhost/books/")
			  .asObject(new GenericType<List<Book>>(){})
			  .getBody();

Author author = Unirest.get("http://localhost/books/{id}/author")
                       .routeParam("id", bookObject.getId())
                       .asObject(Author.class)
                       .getBody();

对象或JSON解析出错时

你不能总是得到你想要的。 有时您从 Web 服务获得的结果不会映射到您期望的结果。 当asObjectasJson 请求发生这种情况时,结果主体将为空,但响应对象将包含一个 ParsingException,允许您获取错误和原始主体以供检查。

UnirestParsingException ex = response.getParsingError().get();

ex.getOriginalBody(); // Has the original body as a string.
ex.getMessage(); // Will have the parsing exception.
ex.getCause(); // of course will have the original parsing exception itself.

映射Erro对象

有时使用 REST API 的服务会返回一个可以解析的错误对象。 您可以选择将其映射到 POJO 中,例如

HttpResponse<Book> book = Unirest.get("http://localhost/books/{id}")
                                     .asObject(Book.class);

    // This will be null if there wasn't an error
    Error er = book.mapError(Error.class);

    // You can also take advantage of this inside of the ifFailure method
    Unirest.get("http://localhost/books/{id}")
           .asObject(Book.class)
           .ifFailure(Error.class, r -> {
                    Error e = r.getBody();
           });

不使用对象映射器将返回的Body映射成一种类型

如果您不想提供完整的 ObjectMapper 实现,您可以使用一个简单的函数来映射响应

int body = Unirest.get("http://httpbin/count")
                      .asString()
                      .mapBody(Integer::valueOf);

File Responses(文件响应)

有时您只是想下载一个文件,或者捕获响应主体到一个文件中。Unirest可以做到这两点。告诉Unirest你想把文件放在哪里。

File result = Unirest.get("http://some.file.location/file.zip")
                .asFile("/disk/location/file.zip")
                .getBody();

下载进度监控

如果您要上传大文件,您可能希望向用户提供一些时间进度条。 您可以通过提供 ProgresMonitor 来监控此进度。

Unirest.get("http://localhost")
                .downLoadMonitor((b, fileName, bytesWritten, totalBytes) -> {
                    updateProgressBarWithBytesLeft(totalBytes - bytesWritten);
                })
                .asFile("/disk/location/file.zip");

JSON responses(JSON 响应)

当您不需要完整的对象映射器时,Unirest 提供了一种轻量级的 JSON 响应类型。

String result = Unirest.get("http://some.json.com")
				       .asJson()
				       .getBody()
				       .getObject()
				       .getJSONObject("car")
				       .getJSONArray("wheels")
				       .get(0)

Large Responses(大响应)

一些响应方法(asStringasJson)将整个响应流读入内存。 为了读取原始流并处理大响应,您可以使用多种函数方法,例如:

Map r = Unirest.get(MockServer.GET)
                .queryString("firstname", "Gary")
                .asObject(i -> new Gson().fromJson(i.getContentReader(), HashMap.class))
                .getBody();

或消费者:

Unirest.get(MockServer.GET)
                .thenConsumeAsync(r -> {
                       // something like writing a file to disk
                });

错误处理

HttpResponse对象有一些处理方法,可以通过链接来处理成功和失败:

  • ifSuccess(Consumer<HttpResponse<T>> response) 将被调用,如果响应是一个200系列的响应,并且任何主体处理(如JsonObject是成功的。
  • ifFailure(Consumer<HttpResponse> response 将在状态为400+或主体处理失败时被调用。

将它们放在一起可能如下所示:

Unirest.get("http://somewhere")
                .asJson()
                .ifSuccess(response -> someSuccessMethod(response))
                .ifFailure(response -> {
                    log.error("Oh No! Status" + response.getStatus());
                    response.getParsingError().ifPresent(e -> {
                        log.error("Parsing Exception: ", e);
                        log.error("Original body: " + e.getOriginalBody());
                    });
                });

缓存

Unirest 提供了一个简单的即时内存响应缓存机制,其中包含一些条目过期选项。 这可以使用默认值、过期选项启用,或者消费者可以提供由他们选择的缓存支持的自定义缓存。 建议在高负载系统中,消费者使用专用缓存实现(如 EHCache 或 Guava)支持缓存。

Basic cache:
Unirest.config().cacheResponses(true);

     //These 1st response will be cached in this case:
     Unirest.get("https://somwhere").asString();
     Unirest.get("https://somwhere").asString();
高级选项:

您可以使用构建器来自定义驱逐规则:

Unirest.config().cacheResponses(builder()
               .depth(5) // Depth is the max number of entries cached
               .maxAge(5, TimeUnit.MINUTES)); // Max age is how long the entry will be kept.
自定义缓存

您还可以通过实现缓存接口来提供自定义缓存

public static void main(String[] args){
       Unirest.config().cacheResponses(Cache.builder().backingCache(new GuavaCache()));
    }

    // Example backing cache using Guava
    public static class GuavaCache implements Cache {
            com.google.common.cache.Cache<Key, HttpResponse> regular = CacheBuilder.newBuilder().build();
            com.google.common.cache.Cache<Key, CompletableFuture> async = CacheBuilder.newBuilder().build();
            @Override
            public <T> HttpResponse get(Key key, Supplier<HttpResponse<T>> fetcher) {
                try {
                    return regular.get(key, fetcher::get);
                } catch (ExecutionException e) {
                    throw new RuntimeException(e);
                }
            }
    
            @Override
            public <T> CompletableFuture getAsync(Key key, Supplier<CompletableFuture<HttpResponse<T>>> fetcher) {
                try {
                    return async.get(key, fetcher::get);
                } catch (ExecutionException e) {
                    throw new RuntimeException(e);
                }
            }
        }

Configuration(配置)

以前版本的unirest配置分散在几个不同的地方。有时在Unirest上完成,有时在Option上完成,有时在其他地方完成。所有配置现在都通过Unirest.config()完成

Unirest.config()
           .socketTimeout(500)
           .connectTimeout(1000)
           .concurrency(10, 5)
           .proxy(new Proxy("https://proxy"))
           .setDefaultHeader("Accept", "application/json")
           .followRedirects(false)
           .enableCookieManagement(false)
           .addInterceptor(new MyCustomInterceptor());

理想情况下,更改 Unirest 的配置应该完成一次,或者很少进行。 Unirest 本身和 Apache HttpAsyncClient 产生了几个后台线程。 一旦 Unirest 被激活,在没有明确关闭或重置的情况下,创建客户端所涉及的配置选项无法更改。

配置选项

Builder 方法描述缺省值
socketTimeout(int)以毫秒为单位设置所有请求的套接字超时60000
connectTimeout(int)以毫秒为单位设置所有请求的连接超时10000
concurrency(int, int)设置并发率; 最大总数,每条路线的最大数量200, 20
proxy(proxy)设置用于协商代理服务器的代理对象。 可以包括身份验证凭据
setDefaultHeader(String, String)设置默认头。如果存在,将覆盖
setDefaultHeader(String, Supplier<String>)按供应商设置默认头。 适合为微服务架构设置跟踪令牌。 如果存在,将覆盖
addDefaultHeader(String, String)添加默认头。可以存在同名的多个
addDefaultHeader(String, Supplier<String>)根据供应商添加一个默认头。适合于为微服务体系结构设置跟踪令牌。
setDefaultBasicAuth(String, String)添加一个默认的Basic认证头
followRedirects(boolean)是否允许重定向true
enableCookieManagement(boolean)是否接受和存储 cookietrue
cookieSpec(String)设置 cookie 策略。 可接受的值:default(与 Netscape 相同)、 netscapeignoreCookiesstandard(RFC 6265 互操作性配置文件)、standard-strict(RFC 6265 严格配置文件)default
automaticRetries(boolean)是否允许套接字超时的自动重试(最多 4 次)true
verifySsl(boolean)是否校验SSLtrue
addShutdownHook(boolean)是否自动将客户端添加到系统关闭钩子中false
clientCertificateStore(String,String)按路径添加 PKCS12 KeyStore 以执行客户端证书
clientCertificateStore(KeyStore,String)添加一个 PKCS12 KeyStore 来做客户端证书
connectionTTL(long,TimeUnit)总生存时间 (TTL) 定义了持久连接的最大生命周期,而不管它们的到期设置如何。 超过其 TTL 值的持久连接将不会被重新使用。-1
connectionTTL(Duration)通过 Duration 添加总生存时间 (TTL)。 适用于现代 Java API。-1
errorHandler(Consumer<HttpResponse<?>> consumer)设置一个全局错误处理程序,该处理程序将在任何状态 > 400 或解析错误时调用
interceptor(Interceptor value)设置一个全局的Interceptor处理程序,在每个请求之前和之后调用它
hostNameVerifier(HostNameVerifier value)为安全配置设置一个自定义的HostNameVerifierDefaultHostNameVerifier
defaultBaseUrl(String value)设置一个默认的基本 URL,用于所有尚未包含scheme的请求

Global Interceptor(全局拦截器)

您可以为您的配置设置一个全局拦截器。 这是在每个请求之前和之后调用的。 这对于记录或注入公共属性很有用。

有关详细信息,请参阅 Interceptor.java

自定义Apache Clients

Unirest 在幕后利用 Apache Http Client,这不被认为是永久性要求,Unirest 的未来版本可能会用其他东西代替 Apache。

您可以设置自己的自定义 Apache HttpClient 和 HttpAsyncClient。 请注意,诸如超时或拦截器之类的 Unirest 设置不适用于自定义客户端。

Unirest.config()
            .httpClient(ApacheClient.builder(myClient))
            .asyncClient(ApacheAsyncClient.builder(myAsyncClient));

您还可以覆盖 Unirest 对 Apache 请求配置的实现

Unirest.config()
            .httpClient(ApacheClient.builder(client)
                .withRequestConfig((c,r) -> RequestConfig.custom().build()
                );

Multiple Configurations

像往常一样,Unirest 维护一个主要的单个实例。 有时您可能需要针对不同系统的不同配置。 出于测试目的,您可能还需要一个实例而不是静态上下文。

// this returns the same instance used by Unirest.get("http://somewhere/")
    UnirestInstance unirest = Unirest.primaryInstance();
    // It can be configured and used just like the static context
    unirest.config().connectTimeout(5000);
    String result = unirest.get("http://foo").asString().getBody();

    // You can also get a whole new instance
    UnirestInstance unirest = Unirest.spawnInstance();

☢警告: 如果您获得了unirest的一个新实例,则您有责任在JVM关闭时关闭它。它没有被’ Unirest.shutDown(); '跟踪或关闭

Object Mappers(对象映射器)

Unirest 提供了一些基于流行的 JSON 库(Jackson 和 GSON)的不同对象映射器。 这些可以作为传统或shaded jars包括在内:

<!-- https://mvnrepository.com/artifact/com.konghq/unirest-objectmapper-jackson -->
<dependency>
    <groupId>com.konghq</groupId>
    <artifactId>unirest-objectmapper-jackson</artifactId>
    <version>3.11.09</version>
</dependency>


<!-- https://mvnrepository.com/artifact/com.konghq/unirest-object-mappers-gson -->
<dependency>
    <groupId>com.konghq</groupId>
    <artifactId>unirest-object-mappers-gson</artifactId>
    <version>3.11.09</version>
</dependency>

如果您有其他需要,您可以通过实现ObjectMapper 接口来提供您自己的对象映射器。 它只有几个方法

Metrics(指标)

Unirest 具有用于收集运行时代码指标的钩子。 这是一个简单的轻量级框架,标记了两个事件:

  1. 发出实际请求之前的那一刻
  2. 发出实际请求后的那一刻

为您提供了方法和请求路径等上下文信息,以便您可以根据需要进行收集。 最简单的形式可能是这样的:

Unirest.config().instrumentWith(requestSummary -> {
              long startNanos = System.nanoTime();
              return (responseSummary,exception) -> logger.info("path: {} status: {} time: {}",
                      requestSummary.getRawPath(),
                      responseSummary.getStatus(),
                      System.nanoTime() - startNanos);
   });

通过提供更多功能丰富的 UniMetric 实例,您可以轻松计算每条 路线(route) 的平均值、正常运行时间或其他有趣的事实。

Shutting Down(关闭)

Unirest启动一个后台事件循环,你的Java应用程序将无法退出,直到你手动关闭所有线程调用:

Unirest.shutdown();


一旦关闭,再次使用 Unirest 将重新初始化系统


<<<<<<<<<<<< [完] >>>>>>>>>>>>

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐