WebClient是从Spring WebFlux 5.0版本开始提供的一个非阻塞的基于响应式编程的进行Http请求的客户端工具。它的响应式编程的基于Reactor的。WebClient中提供了标准Http请求方式对应的get、post、put、delete等方法,可以用来发起相应的请求。 增加pom引用 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-webflux</artifactId> </dependency> 简单例子下面的代码是一个简单的WebClient请求示例。可以通过WebClient.create()创建一个WebClient的实例,之后可以通过get()、post()等选择调用方式,uri()指定需要请求的路径,retrieve()用来发起请求并获得响应,bodyToMono(String.class)用来指定请求结果需要处理为String,并包装为Reactor的Mono对象。 WebClient webClient = WebClient.create();
Mono<String> mono = webClient.get().uri("https://www.baidu.com").retrieve().bodyToMono(String.class);
System.out.println(mono.block());
URL中使用路径变量URL中也可以使用路径变量,路径变量的值可以通过uri方法的第2个参数指定。下面的代码中就定义了URL中拥有一个路径变量id,然后实际访问时该变量将取值1。 webClient.get().uri("http://localhost:8081/user/{id}", 1); URL中也可以使用多个路径变量,多个路径变量的赋值将依次使用uri方法的第2个、第3个、第N个参数。下面的代码中就定义了URL中拥有路径变量p1和p2,实际访问的时候将被替换为var1和var2。所以实际访问的URL是 webClient.get().uri("http://localhost:8081/user/{p1}/{p2}", "var1", "var2"); 使用的路径变量也可以通过Map进行赋值。面的代码中就定义了URL中拥有路径变量p1和p2,实际访问的时候会从uriVariables中获取值进行替换。所以实际访问的URL是 Map<String, Object> uriVariables = new HashMap<>();
uriVariables.put("p1", "var1");
uriVariables.put("p2", 1);
webClient.get().uri("http://localhost:8081/user/{p1}/{p2}", uriVariables);
使用uriBuilder传递参数String baseUrl = "http://192.1681.5.9:8989"; 指定baseUrl在应用中使用WebClient时也许你要访问的URL都来自同一个应用,只是对应不同的URL地址,这个时候可以把公用的部分抽出来定义为baseUrl,然后在进行WebClient请求的时候只指定相对于baseUrl的URL部分即可。这样的好处是你的baseUrl需要变更的时候可以只要修改一处即可。下面的代码在创建WebClient时定义了baseUrl为 String baseUrl = "http://localhost:8081";
WebClient webClient = WebClient.create(baseUrl);
Mono<User> mono = webClient.get().uri("user/{id}", 1).retrieve().bodyToMono(User.class);
Form提交当传递的请求体对象是一个MultiValueMap对象时,WebClient默认发起的是Form提交。下面的代码中就通过Form提交模拟了用户进行登录操作,给Form表单传递了参数username,值为u123,传递了参数password,值为p123。 String baseUrl = "http://localhost:8081"; WebClient webClient = WebClient.create(baseUrl); MultiValueMap<String, String> map = new LinkedMultiValueMap<>(); map.add("username", "u123"); map.add("password", "p123"); Mono<String> mono = webClient.post().uri("/login").syncBody(map).retrieve().bodyToMono(String.class); 请求JSON假设现在拥有一个新增User的接口,按照接口定义客户端应该传递一个JSON对象,格式如下: { "name":"张三", "username":"zhangsan" } 客户端可以建立一个满足需要的JSON格式的对象,然后直接把该对象作为请求体,WebClient会帮我们自动把它转换为JSON对象。 String baseUrl = "http://localhost:8081"; WebClient webClient = WebClient.create(baseUrl); User user = new User(); user.setName("张三"); user.setUsername("zhangsan"); Mono<Void> mono = webClient.post().uri("/user/add").syncBody(user).retrieve().bodyToMono(Void.class); mono.block(); 如果没有建立对应的对象,直接包装为一个Map对象也是可以的,比如下面这样。 String baseUrl = "http://localhost:8081"; WebClient webClient = WebClient.create(baseUrl); Map<String, Object> user = new HashMap<>(); user.put("name", "张三"); user.put("username", "zhangsan"); Mono<Void> mono = webClient.post().uri("/user/add").syncBody(user).retrieve().bodyToMono(Void.class); mono.block(); 直接传递一个JSON字符串也是可以的,但是此时需要指定contentType为 String baseUrl = "http://localhost:8081";
WebClient webClient = WebClient.create(baseUrl);
String userJson =
"{" +
" \"name\":\"张三\",\r\n" +
" \"username\":\"zhangsan\"\r\n" +
"}";
Mono<Void> mono = webClient.post().uri("/user/add").contentType(MediaType.APPLICATION_JSON_UTF8).syncBody(userJson).retrieve().bodyToMono(Void.class);
mono.block();
处理WebClient错误WebClient.ResponseSpec retrieve = request.retrieve(); 上传和下载文件上传 HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.IMAGE_PNG); HttpEntity<ClassPathResource> entity = new HttpEntity<>(new ClassPathResource("parallel.png"), headers); MultiValueMap<String, Object> parts = new LinkedMultiValueMap<>(); parts.add("file", entity); Mono<String> resp = WebClient.create().post() .uri("http://localhost:8080/upload") .contentType(MediaType.MULTIPART_FORM_DATA) .body(BodyInserters.fromMultipartData(parts)) .retrieve().bodyToMono(String.class); LOGGER.info("result:{}",resp.block()); 下载图片 Mono<Resource> resp = WebClient.create().get() .uri("http://www./captcha?complexity=99&size=60&length=9") .accept(MediaType.IMAGE_PNG) .retrieve().bodyToMono(Resource.class); Resource resource = resp.block(); BufferedImage bufferedImage = ImageIO.read(resource.getInputStream()); ImageIO.write(bufferedImage, "png", new File("captcha.png")); 下载文件 Mono<ClientResponse> resp = WebClient.create().get() .uri("http://localhost:8080/file/download") .accept(MediaType.APPLICATION_OCTET_STREAM) .exchange(); ClientResponse response = resp.block(); String disposition = response.headers().asHttpHeaders().getFirst(HttpHeaders.CONTENT_DISPOSITION); String fileName = disposition.substring(disposition.indexOf("=")+1); Resource resource = response.bodyToMono(Resource.class).block(); File out = new File(fileName); FileUtils.copyInputStreamToFile(resource.getInputStream(),out); LOGGER.info(out.getAbsolutePath()); 异步调用Flux<String> flux = request.retrieve().bodyToFlux(String.class); Disposable subscribe = flux.subscribe(tweet -> { //如果jvm结束了,就不能显示了 System.out.println(tweet.toString()); }); System.out.println("result:exit"); Thread.sleep(5000); exchange前面介绍的示例都是直接获取到了响应的内容,可能你会想获取到响应的头信息、Cookie等。那就可以在通过WebClient请求时把调用 String baseUrl = "http://localhost:8081"; WebClient webClient = WebClient.create(baseUrl); MultiValueMap<String, String> map = new LinkedMultiValueMap<>(); map.add("username", "u123"); map.add("password", "p123"); Mono<ClientResponse> mono = webClient.post().uri("login").syncBody(map).exchange(); ClientResponse response = mono.block(); if (response.statusCode() == HttpStatus.OK) { Mono<Result> resultMono = response.bodyToMono(Result.class); resultMono.subscribe(result -> { if (result.isSuccess()) { ResponseCookie sidCookie = response.cookies().getFirst("sid"); Flux<User> userFlux = webClient.get().uri("users").cookie(sidCookie.getName(), sidCookie.getValue()).retrieve().bodyToFlux(User.class); userFlux.subscribe(System.out::println); } }); } WebClient.Builder除了可以通过 String baseUrl = "http://localhost:8081"; WebClient webClient = WebClient.builder().baseUrl(baseUrl).defaultCookie("cookieName", "cookieValue").build(); //使用WebClient构建器,可以自定义选项:包括过滤器、默认标题、cookie、客户端连接器等 WebClient webClient = WebClient.builder() .baseUrl("https://api.github.com") .defaultHeader(HttpHeaders.CONTENT_TYPE, "application/vnd.github.v3+json") .defaultHeader(HttpHeaders.USER_AGENT, "Spring 5 WebClient") .build() Builder还可以通过 <dependency> <groupId>io.projectreactor.ipc</groupId> <artifactId>reactor-netty</artifactId> <version>0.7.8.RELEASE</version> </dependency> 如果对默认的发送请求和处理响应结果的编解码不满意,还可以通过exchangeStrategies()定义使用的ExchangeStrategies。ExchangeStrategies中定义了用来编解码的对象,其也有对应的build()方法方便我们来创建ExchangeStrategies对象。 WebClient也提供了Filter,对应于org.springframework.web.reactive.function.client.ExchangeFilterFunction接口,其接口方法定义如下。 Mono<ClientResponse> filter(ClientRequest request, ExchangeFunction next) 在进行拦截时可以拦截request,也可以拦截response。下面的代码定义的Filter就拦截了request,给每个request都添加了一个名为header1的header,值为value1。它也拦截了response,response中也是添加了一个新的header信息。拦截response时,如果新的ClientResponse对象是通过 String baseUrl = "http://localhost:8081"; WebClient webClient = WebClient.builder().baseUrl(baseUrl).filter((request, next) -> { ClientRequest newRequest = ClientRequest.from(request).header("header1", "value1").build(); Mono<ClientResponse> responseMono = next.exchange(newRequest); return Mono.fromCallable(() -> { ClientResponse response = responseMono.block(); ClientResponse newResponse = ClientResponse.from(response).header("responseHeader1", "Value1").build(); return newResponse; }); }).build(); 如果定义的Filter只期望对某个或某些request起作用,可以在Filter内部通过request的相关属性进行拦截,比如cookie信息、header信息、请求的方式或请求的URL等。也可以通过 配置连接池,超时时间等@Configuration public class WebClientConfig { @Bean ReactorResourceFactory resourceFactory() { ReactorResourceFactory factory = new ReactorResourceFactory(); factory.setUseGlobalResources(false); factory.setConnectionProvider(ConnectionProvider.fixed("httpClient", 50, 10)); factory.setLoopResources(LoopResources.create("httpClient", 50, true)); return factory; } @Bean WebClient webClient() { Function<HttpClient, HttpClient> mapper = client -> client.tcpConfiguration(c -> c.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 10) .option(TCP_NODELAY, true) .doOnConnected(conn -> { conn.addHandlerLast(new ReadTimeoutHandler(10)); conn.addHandlerLast(new WriteTimeoutHandler(10)); })); ClientHttpConnector connector = new ReactorClientHttpConnector(resourceFactory(), mapper); return WebClient.builder().clientConnector(connector).build(); } }
参数 https://blog.csdn.net/iteye_13139/article/details/82726588 https://segmentfault.com/a/1190000012916413 https:///post/5d6c9507e51d4561f777e20b https://docs./spring/docs/current/spring-framework-reference/web-reactive.html#webflux-client
|
|
来自: vnxy001 > 《021springboot》