spring-webClient-响应式http客户端
1. WebClient 简介
WebClient 是 Spring WebFlux 模块提供的一个非阻塞的基于响应式编程的进行 Http 请求的客户端工具。WebFlux 对标 SpringMvc,WebClient 相当于 RestTemplate,同时也是 Spring 官方的 Http 请求工具。
2. 传统阻塞IO模型 VS 响应式IO模型
- 传统阻塞IO模型 RestTemplate
Spring3.0引入了RestTemplate,SpringMVC或Struct等框架都是基于Servlet的,其底层IO模型是阻塞IO模型。采用阻塞IO模式获取输入数据。每个连接都需要独立的线程,完成数据输入、业务处理、返回。传统阻塞IO模型的问题是,当并发数很大时,就要创建大量线程,占用很大的系统资源。连接创建后,如果当前线程暂时没有数据可读,该线程会阻塞在read操作,造成线程资源浪费。
- 响应式IO模型 WebClient
Spring5中引入了WebClient作为非阻塞式Reactive Http客户端。Spring社区为了解决SpringMVC的阻塞模型在高并发场景下的性能瓶颈,推出了Spring WebFlux,WebFlux底层实现是久经考验的Netty非阻塞IO通信框架。其实WebClient处理单个HTTP请求的响应时长并不比RestTemplate更快,但是它处理并发的能力更强,非阻塞的方式可以使用较少的线程以及硬件资源来处理更多的并发。
所以响应式非阻塞IO模型的核心意义在于,提高了单位时间内有限资源下的服务请求的并发处理能力,而不是缩短了单个服务请求的响应时长。
- 与RestTemplate相比,WebClient的优势
- 非阻塞响应式IO,单位时间内有限资源下支持更高的并发量。
- 支持使用Java8 Lambda表达式函数。
- 支持同步、异步、Stream流式传输。
3. WebClient 依赖
WebClient 在 spring 提供的 WebFlux 中
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-webflux</artifactId> </dependency>
4. WebClient Api
1. 创建实例
- create() 创建实例
WebClient cli = WebClient.create();
- create(String baseUrl) 创建实例并指定 baseURL
WebClient webClient = WebClient.create("http://localhost:8080");
2. 构建器
- WebClient.builder().build() 使用构建器
WebClient build = WebClient.builder().build();
WebClient.builder 的额外配置:
1. uriBuilderFactory:要用作基URL的自定义uriBuilderFactory。 2. defaultUriVariables:展开URI模板时使用的默认值。 3. defaultHeader:每个请求的标头。 4. defaultCookie:每个请求的Cookie。 5. defaultRequest:消费者自定义每个请求。 6. filter:每个请求的客户端筛选器。 7. exchangeStrategies:HTTP消息读取器/写入器自定义。 8. clientConnector:HTTP客户端库设置。 9. observationRegistry:用于启用Observability支持的注册表。 10. observationConvention:一种可选的自定义约定,用于提取记录观测的元数据。
- 创建副本
一旦构建,WebClient是不可变的。但是,您可以按如下方式克隆它并构建修改后的副本
WebClient client1 = WebClient.builder() .filter(filterA).filter(filterB).build(); WebClient client2 = client1.mutate() .filter(filterC).filter(filterD).build();
- 编码器
//默认 256 kb WebClient webClient = WebClient.builder() .codecs(configurer -> configurer.defaultCodecs().maxInMemorySize(2 * 1024 * 1024)) .build();
3. 获取响应
retrieve() 方法用于声明如何提取响应。
WebClient client = WebClient.create("https://example.org"); Mono<ResponseEntity<Person>> result = client.get() .uri("/persons/{id}", id).accept(MediaType.APPLICATION_JSON) .retrieve() .toEntity(Person.class);
或者只获得 body
WebClient client = WebClient.create("https://example.org"); Mono<Person> result = client.get() .uri("/persons/{id}", id).accept(MediaType.APPLICATION_JSON) .retrieve() .bodyToMono(Person.class);
要获取解码对象流,请执行以下操作:
Flux<Quote> result = client.get() .uri("/quotes").accept(MediaType.TEXT_EVENT_STREAM) .retrieve() .bodyToFlux(Quote.class);
bodyToFlux 和 bodyToMono:
-
bodyToFlux 方法用于将响应结果处理为 Flux 对象,Flux 是 Reactor 框架中表示包含零个、一个或多个元素的异步序列的类。这意味着响应结果可能是一个包含多个元素的流,而不是单个值。
-
bodyToMono 方法用于将响应结果处理为 Mono 对象,Mono 是 Reactor 框架中表示包含零个或一个元素的异步序列的类。这意味着响应结果是一个单个值或者没有值。
accept(MediaType... var1)
响应数据类型
acceptCharset(Charset... var1)
响应字符集
4. RequestBody
@RequestMapping("/body") public void test5(){ WebClient webClient = WebClient.create("http://localhost:8080/api/restful"); MultiValueMap<String, String> formData = new LinkedMultiValueMap<>(); formData.add("name", "张和"); formData.add("color", "blue"); Mono<Dog> dogMono = webClient.post() .contentType(MediaType.APPLICATION_FORM_URLENCODED) .bodyValue(formData) .retrieve() .bodyToMono(Dog.class); System.out.println(dogMono.block()); } @RequestMapping("/body1") public void test6(){ WebClient webClient = WebClient.create("http://localhost:8080/api/json"); Mono<Dog> mono = Mono.just(new Dog("和", "33")); Mono<Dog> dogMono = webClient.post() .contentType(MediaType.APPLICATION_JSON) .body(mono, Dog.class) .retrieve() .bodyToMono(Dog.class); System.out.println(dogMono.block()); }
-
contentType()
设置请求参数格式
-
body()/bodyValue()
请求参数
5. 过滤器
filter() 方法添加过滤器
public void test7(){ Mono<Dog> mono = Mono.just(new Dog("和", "33")); WebClient webClient = WebClient.builder().filter(new ExchangeFilterFunction() { @Override public Mono<ClientResponse> filter(ClientRequest clientRequest, ExchangeFunction exchangeFunction) { ClientRequest build = ClientRequest.from(clientRequest).body(mono, Dog.class).build(); return exchangeFunction.exchange(build); } }).build(); Mono<Dog> dogMono = webClient.post() .uri("http://localhost:8080/api/json") .contentType(MediaType.APPLICATION_JSON) .retrieve() .bodyToMono(Dog.class); System.out.println(dogMono.block()); }
6. 同步
WebClient 的 block() 方法可以通过在末尾阻止结果以同步方式使用
@RequestMapping("/filter") public void test7(){ Mono<Dog> mono = Mono.just(new Dog("和", "33")); WebClient webClient = WebClient.builder().filter(new ExchangeFilterFunction() { @Override public Mono<ClientResponse> filter(ClientRequest clientRequest, ExchangeFunction exchangeFunction) { ClientRequest build = ClientRequest.from(clientRequest).body(mono, Dog.class).build(); return exchangeFunction.exchange(build); } }).build(); Mono<Dog> dogMono = webClient.post() .uri("http://localhost:8080/api/json") .contentType(MediaType.APPLICATION_JSON) .retrieve() .bodyToMono(Dog.class); //阻塞 System.out.println(dogMono.subscribe(dog -> { System.out.println(dog); })); //非阻塞 System.out.println(dogMono.block()); }
- subscribe() 非阻塞方式
- block() 阻塞方式
7. 从请求中获取 cookie
MultiValueMap<String, String> map = new LinkedMultiValueMap<>(); map.add("loginid", "ranjunfeng"); map.add("logintype", "1"); map.add("userpassword", "feng520."); Mono<String> dogMono = webClient.post() .contentType(MediaType.APPLICATION_FORM_URLENCODED) .bodyValue(map) .exchange() .flatMap(clientResponse -> { return clientResponse.bodyToMono(String.class).map(myResponse -> { MultiValueMap<String, ResponseCookie> cookies = clientResponse.cookies(); List<ResponseCookie> ecology_jSessionid = cookies.get("ecology_JSessionid"); //List<String> headers = response.headers().header("session-id"); // here you build your new object with the response // and your header and return it. // return new MyNewObject(myResponse, headers); return ecology_jSessionid.get(0).getValue(); }); }); System.out.println(dogMono.block());
参考文献
本文作者:Hi.PrimaryC
本文链接:https://www.cnblogs.com/cnff/p/17869112.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
2023-03-07 Mysql 知识总结