接上一篇 RestTemplate的basic auth使用;
在spring5后官方带来了WebClient,说是以后替代RestTemplate了,不知道真假哈,既然有了新东西,就研究一下使用方法呗,也同时做个备忘笔记。
老规矩,先上结果,后说问题:
import org.springframework.http.HttpHeaders;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.List;
import java.util.Map;
public class WebClientRequest {
private static WebClient webClient = WebClient.builder()
.baseUrl("http://jsonplaceholder.typicode.com")
.build();
private static void getHttp() throws InterruptedException {
//同步阻塞处理
//返回单个对象的处理
Mono<Map> result = webClient.get().uri("/posts/1").headers(headers -> headers.setBasicAuth("username", "password")).retrieve().bodyToMono(Map.class);
System.out.println("result.block()>>>>>>>>>" + result.block().get("title"));
返回数组的处理 小数据量用Mono<List>没有问题,数据量大了就会出超出buffer的异常了
Mono<List> result = webClient.get().uri("/posts").headers(headers -> headers.setBasicAuth("username", "password")).retrieve().bodyToMono(List.class);
System.out.println("result.block()>>>>>>>>>" + ((Map)result.block().get(0)).get("title"));
返回数组的处理 数组还是推荐使用Flux来处理,不会出现超出buffer的问题
Flux<Map> result = webClient.get().uri("/posts").headers(headers -> headers.setBasicAuth("username", "password")).retrieve().bodyToFlux(Map.class);
System.out.println("result.block()>>>>>>>>>" + result.collectList().block().get(0).get("title"));
//异步非阻塞处理
//返回单个对象的处理
Mono<Map> result = webClient.get().uri("/posts/1").headers(headers -> headers.setBasicAuth("username", "password")).retrieve().bodyToMono(Map.class);
result.subscribe(System.out::println);
返回数组的处理
Flux<Map> result = webClient.get().uri("/posts").headers(headers -> headers.setBasicAuth("username", "password")).retrieve().bodyToFlux(Map.class);
result.subscribe(System.out::println);
// 等待3秒,防止主进程结束看不到异步消息打印
Thread.currentThread().sleep(3000);
}
public static void main(String[] args) throws InterruptedException {
getHttp();
}
}
WebClient也可以同步阻塞线程,也可以异步非阻塞线程,看大家具体使用情况了。这里主要说一下认证,我使用的方式应该是代码最简洁的官方方法了,但是仍然有人使用Base64.getEncoder(),那样代码就不够简洁了,如下就比较繁琐:
public static void testWithBasicAuth() {
String url = "http://XXXXXXXXXXXXXXXXXXXXXXXX";
String basicAuth = "Basic " + Base64.getEncoder().encodeToString("username:password".getBytes(StandardCharsets.UTF_8));
System.out.println(basicAuth);
Mono<String> resp = WebClient.create().get().uri(url).header(HttpHeaders.AUTHORIZATION, basicAuth).retrieve().bodyToMono(String.class);
System.out.println(resp.block());
}
下面说说遇到的一个小问题,在测试时发生了异常,接口调用返回200,后续打印处理出错,说是Exceeded limit on max bytes to buffer : 262144,于是baidu查找原因,基本上都说增加缓存设置来解决。但是分析了一下数据后发现,接口给的数据是数组,我在接收后转成了Map,这就相当于把List转成Map,那肯定不行啊,于是更改代码,把接收后数据转成List就一切ok了。
这个小坑是我类型匹配没使用对,但是异常告诉我超出buffer缓存了,就不能直接告诉我类型转换不匹配吗,折腾了一下午。。。马虎不得啊!
Suppressed: java.lang.Exception: #block terminated with an error
at reactor.core.publisher.BlockingSingleSubscriber.blockingGet(BlockingSingleSubscriber.java:99)
at reactor.core.publisher.Mono.block(Mono.java:1703)
at com.xuyang.datacenter.WebClientRequest.getHttp(WebClientRequest.java:62)
at com.xuyang.datacenter.WebClientRequest.main(WebClientRequest.java:90)
Caused by: org.springframework.core.io.buffer.DataBufferLimitException: Exceeded limit on max bytes to buffer : 262144
at org.springframework.core.io.buffer.LimitedDataBufferList.raiseLimitException(LimitedDataBufferList.java:98)
Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException:
Error has been observed at the following site(s):
|_ checkpoint ⇢ Body from GET http://oa.risun.com/indishare/indinames.nsf/api/data/collections/name/vwDepByAllForOther_xm?keys=&_rt=201909231718&count=9999&keysexactmatch=true [DefaultClientResponse]
Stack trace:
at org.springframework.core.io.buffer.LimitedDataBufferList.raiseLimitException(LimitedDataBufferList.java:98)
at org.springframework.core.io.buffer.LimitedDataBufferList.updateCount(LimitedDataBufferList.java:91)
at org.springframework.core.io.buffer.LimitedDataBufferList.add(LimitedDataBufferList.java:57)
参考网址:https://www.viralpatel.net/basic-authentication-spring-webclient/