版本: 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/](https://kong.github.io/unirest-java/),而且可以看到,除了Java的api,还提供了Python、PHP、Nodejs等不同语言的支持。顺带说一句,Unirest-Java的github地址为[https://github.com/kong/unirest-java/](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.12.0</version></dependency><!-- OR as a snazzy new standalone jar with shaded dependencies --><dependency><groupId>com.konghq</groupId><artifactId>unirest-java</artifactId><version>3.12.0</version><classifier>standalone</classifier></dependency>
用 Gradle: 安装
// Make sure you added the mavencentral repositoryrepositories {mavenCentral()}// Pull in as a traditional dependencydependencies {// ... Your other dependenciesimplementation 'com.konghq:unirest-java:3.11.09'}// OR as a snazzy new standalonedependencies {// ... Your other dependenciesimplementation 'com.konghq:unirest-java:3.11.09: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 ‘被调用时发出请求,可能的类型包括Json, String, Object, Empty和File。
路由(路径)参数
有时您想在 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-Type 是 text/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-Type 是 application/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 withoutUnirest.config().proxy("proxy.com", 7777);// or pass it in the request. This will override any proxy done in the config// currently only unauthenticated proxies workUnirest.get(MockServer.GET).proxy("proxy.com", 7777).asString();
Responses(响应)
Unirest 在您调用它的 as[type] 方法时发出实际请求。 这些方法还通知 Unirest 将响应映射到什么类型。 选项有Empty、String、File、Object、byte和Json。
响应返回一个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 ObjectBook book = Unirest.get("http://localhost/books/1").asObject(Book.class).getBody();// Generic types can be resolved by using a GenericType subclass to avoid erasureList<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 服务获得的结果不会映射到您期望的结果。 当asObject 或asJson 请求发生这种情况时,结果主体将为空,但响应对象将包含一个 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 errorError er = book.mapError(Error.class);// You can also take advantage of this inside of the ifFailure methodUnirest.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(大响应)
一些响应方法(asString、asJson)将整个响应流读入内存。 为了读取原始流并处理大响应,您可以使用多种函数方法,例如:
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系列的响应,并且任何主体处理(如Json或Object是成功的。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 Guavapublic 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();@Overridepublic <T> HttpResponse get(Key key, Supplier<HttpResponse<T>> fetcher) {try {return regular.get(key, fetcher::get);} catch (ExecutionException e) {throw new RuntimeException(e);}}@Overridepublic <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) |
是否接受和存储 cookie | true |
cookieSpec(String) |
设置 cookie 策略。 可接受的值:default(与 Netscape 相同)、 netscape、ignoreCookies、standard(RFC 6265 互操作性配置文件)、standard-strict(RFC 6265 严格配置文件) |
default |
automaticRetries(boolean) |
是否允许套接字超时的自动重试(最多 4 次) | true |
verifySsl(boolean) |
是否校验SSL | true |
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) |
为安全配置设置一个自定义的HostNameVerifier | DefaultHostNameVerifier |
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 contextunirest.config().connectTimeout(5000);String result = unirest.get("http://foo").asString().getBody();// You can also get a whole new instanceUnirestInstance 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 具有用于收集运行时代码指标的钩子。 这是一个简单的轻量级框架,标记了两个事件:
- 发出实际请求之前的那一刻
- 发出实际请求后的那一刻
为您提供了方法和请求路径等上下文信息,以便您可以根据需要进行收集。 最简单的形式可能是这样的:
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 将重新初始化系统
