原创:花括号MC(微信公众号:huakuohao-mc),欢迎分享,转载请保留出处。
WebClient
是Spring5
引入的,基于响应式编程实现的HTTP
调用客户端。Spring
官方推荐使用WebClient
替代RestTemplate
完成HTTP
调用。因为WebClient
是基于Reactor
实现的,所以既可以支持阻塞调用也可以支持非阻塞调用,在高并发的场景下资源利用率更高。这也是官方推荐使用的重要原因之一。
如果大家不了解响应式编程,强烈建议可以先看一下我这篇文章,这样对本篇文章中的样例代码也会有些帮助。
如果在工程中想要是用WebClient
,在Pom
文件中加入如下依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
复制代码
如果使用的是Gradle
,则加入如下依赖
dependencies {
compile 'org.springframework.boot:spring-boot-starter-webflux'
}
复制代码
初始化WebClient
- 直接初始化,不加任何参数。
WebClient client = WebClient.create();
复制代码
- 初始化时,提供一个默认的调用地址。
WebClient client = WebClient.create("http://localhost:8080");
复制代码
- 自定义参数初始化。
WebClient client = WebClient.builder()
.baseUrl("http://localhost:8080")
.defaultCookie("cookieKey", "cookieValue")
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.defaultUriVariables(Collections.singletonMap("url", "http://localhost:8080"))
.build();
复制代码
- 修改默认的超时时间。
//通过HttpClient设置超时时间
HttpClient httpClient = HttpClient.create()
//设置连接超时时间
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000)
//设置响应超时时间
.responseTimeout(Duration.ofMillis(5000))
//分别设置读写超时时间
.doOnConnected(conn -> conn.addHandlerLast(new ReadTimeoutHandler(5000, TimeUnit.MILLISECONDS)) .addHandlerLast(new WriteTimeoutHandler(5000,TimeUnit.MILLISECONDS)));
WebClient client = WebClient.builder()
.clientConnector(new ReactorClientHttpConnector(httpClient))
.build();
复制代码
发起Get请求
- 以阻塞的方式获取0或者1个返回结果,用
Mono
表示
//通过builder的方式初始化
WebClientWebClient webClient = WebClient.builder() //配置头部信息
.defaultHeader(HttpHeaders.ACCEPT_CHARSET, "UTF-8")
//定义过滤器
.filter(ExchangeFilterFunctions.basicAuthentication("user","password"))
.filter((clientRequest, next) -> {
logger.info("Request: {} {}",clientRequest.method(),clientRequest.url());
clientRequest.headers()
.forEach((name, values) -> values.forEach(value
-> logger.info("{}={}", name, value)));
return next.exchange(clientRequest);
})
.build();
//发起GET请求
Mono<String> resp = webClient.get()
.uri("https://localhost:8080")
//获取结果
.retrieve()
//将结果转化为指定类型
.bodyToMono(String.class);
//以阻塞的方式将结果打印出来
logger.info("result:{}",resp.block());
复制代码
- 以阻塞方式获取多个返回结果,用
Flux
表示
Flux<Book> bookFlux = WebClient.create()
.method(HttpMethod.GET)
.uri("http://localhost:8080/books")
.retrieve()
.bodyToFlux(Book.class);
//通过阻塞的方式获取响应结果
List<Book> books = bookFlux.collectList().block();
//通过非阻塞的方式获取响应结果
bookFlux.subscribe(book ->{System.out.print(book.getName());});
复制代码
- 通过非阻塞方式获取响应结果
Flux<Book> bookFlux = WebClient.create()
.method(HttpMethod.GET)
.uri("http://localhost:8080/books")
.retrieve()
.bodyToFlux(Book.class);
//通过非阻塞的方式获取响应结果
bookFlux.subscribe(book ->{System.out.print(book.getName());});
复制代码
- 通过占位符传参
Mono<String> mono = WebClient.create()
.method(HttpMethod.POST)
.uri("http://localhost:8080/book/{id}/{name}", "1", "java")
.retrieve()
.bodyToMono(String.class);
String result = mono.block();
复制代码
除了占位符传参,还可以通过map形式传参等等,这里不一一举例介绍了。
发起POST请求
- 发起
POST
请求,提交Form
表单
MultiValueMap<String, String> formData = new
LinkedMultiValueMap<>();
formData.add("name1","value1");
formData.add("name2","value2");
Mono<String> resp = WebClient.create().post()
.uri("http://localhost:8080/submit") .contentType(MediaType.APPLICATION_FORM_URLENCODED)
.body(BodyInserters.fromFormData(formData)) .retrieve().bodyToMono(String.class);
logger.info("result:{}",resp.block());
复制代码
- 使用
Raw Json
的方式发起POST
请求。
Mono<String> resp = WebClient.create().post()
.uri("http://localhost:8080/book/json")
.contentType(MediaType.APPLICATION_JSON)
.body(BodyInserters.fromValue("{\n" + " \"name\" : \"java\",\n" + " \"price\" : \"32.5\" \n" + " }")) .retrieve().bodyToMono(String.class);
logger.info("result:{}",resp.block());
复制代码
错误和异常处理
WebClient可以更优雅的处理错误和异常。
//创建WebClient
WebClient webClient = WebClient.builder()
.baseUrl("http://localhost:8080")
.defaultHeader(HttpHeaders.CONTENT_TYPE, "application/json")
.defaultHeader(HttpHeaders.ACCEPT_CHARSET, "UTF-8")
.build();
//发起Get请求
WebClient.ResponseSpec responseSpec = webClient.method(HttpMethod.GET)
.uri("/book/remark/{id}", "1")
.retrieve();
//根据状态码进行响应
Mono<String> mono = responseSpec
.onStatus(e -> e.is4xxClientError(),resp -> {
logger.error("error:{},msg:{}",resp.statusCode().value(),resp.statusCode().getReasonPhrase());
return Mono.error(new RuntimeException(resp.statusCode().value() + " : " + resp.statusCode().getReasonPhrase()));
})
.bodyToMono(String.class)
.doOnError(WebClientResponseException.class, err -> {
logger.info("ERROR status:{},msg:{}",err.getRawStatusCode(),err.getResponseBodyAsString());
throw new RuntimeException(err.getMessage());
})
.onErrorReturn("fallback");
String result = mono.block();
logger.info("result:{}",result);
复制代码
总结
以上是一些WebClient
使用的小Demo
,希望对那些想了解WebClient
的同学有一些帮助。如果想深入了解,建议还是多看看官方文档。
推荐阅读
原创:花括号MC(微信公众号:huakuohao-mc)。关注JAVA基础编程及大数据,注重经验分享及个人成长。
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END