当前位置:首页 > 科技  > 软件

别再使用 RestTemplate了,来了解一下官方推荐的 WebClient !

来源: 责编: 时间:2023-10-10 18:32:44 930观看
导读在 Spring Framework 5.0 及更高版本中,RestTemplate 已被弃用,取而代之的是较新的 WebClient。这意味着虽然 RestTemplate 仍然可用,但鼓励 Spring 开发人员迁移到新项目的 WebClient。WebClient 优于 RestTemplate 的

在 Spring Framework 5.0 及更高版本中,RestTemplate 已被弃用,取而代之的是较新的 WebClient。这意味着虽然 RestTemplate 仍然可用,但鼓励 Spring 开发人员迁移到新项目的 WebClient。MhG28资讯网——每日最新资讯28at.com

WebClient 优于 RestTemplate 的原因有几个:MhG28资讯网——每日最新资讯28at.com

  • 非阻塞 I/O:WebClient 构建在 Reactor 之上,它提供了一种非阻塞、反应式的方法来处理 I/O。这可以在高流量应用程序中实现更好的可扩展性和更高的性能。
  • 函数式风格:WebClient 使用函数式编程风格,可以使代码更易于阅读和理解。它还提供了流畅的 API,可以更轻松地配置和自定义请求。
  • 更好地支持流式传输:WebClient 支持请求和响应正文的流式传输,这对于处理大文件或实时数据非常有用。
  • 改进的错误处理:WebClient 提供比 RestTemplate 更好的错误处理和日志记录,从而更轻松地诊断和解决问题。

重点:即使升级了spring web 6.0.0版本,也无法在HttpRequestFactory中设置请求超时,这是放弃使用 RestTemplate 的最大因素之一。MhG28资讯网——每日最新资讯28at.com

图片图片MhG28资讯网——每日最新资讯28at.com

设置请求超时不会有任何影响MhG28资讯网——每日最新资讯28at.com

总的来说,虽然 RestTemplate 可能仍然适用于某些用例,但 WebClient 提供了几个优势,使其成为现代 Spring 应用程序的更好选择。MhG28资讯网——每日最新资讯28at.com

让我们看看如何在 SpringBoot 3 应用程序中使用 WebClient。MhG28资讯网——每日最新资讯28at.com

(1) 创建网络客户端:

import ioty.channel.ChannelOption;import ioty.channel.ConnectTimeoutException;import ioty.handler.timeout.ReadTimeoutException;import ioty.handler.timeout.ReadTimeoutHandler;import ioty.handler.timeout.TimeoutException;import jakarta.annotation.PostConstruct;import java.time.Duration;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Value;import org.springframework.http.HttpMethod;import org.springframework.http.MediaType;import org.springframework.http.client.reactive.ReactorClientHttpConnector;import org.springframework.stereotype.Service;import org.springframework.web.reactive.function.client.WebClient;import org.springframework.web.reactive.function.client.WebClientRequestException;import org.springframework.web.reactive.function.client.WebClientResponseException;import reactor.core.publisher.Mono;import reactorty.http.client.HttpClient;HttpClient httpClient =        HttpClient.create()            .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, connectionTimeout)            .responseTimeout(Duration.ofMillis(requestTimeout))            .doOnConnected(conn -> conn.addHandlerLast(new ReadTimeoutHandler(readTimeout)));   WebClient client =        WebClient.builder().clientConnector(new ReactorClientHttpConnector(httpClient)).build();

(2) 同步发送请求(就像RestTemplate一样)

如果你想坚持使用发送 HTTP 请求并等待响应的老方法,也可以使用 WebClient 实现如下所示的相同功能:MhG28资讯网——每日最新资讯28at.com

public String postSynchronously(String url, String requestBody) {  LOG.info("Going to hit API - URL {} Body {}", url, requestBody);  String response = "";  try {    response =        client            .method(HttpMethod.POST)            .uri(url)            .accept(MediaType.ALL)            .contentType(MediaType.APPLICATION_JSON)            .bodyValue(requestBody)            .retrieve()            .bodyToMono(String.class)            .block();  } catch (Exception ex) {    LOG.error("Error while calling API ", ex);    throw new RunTimeException("XYZ service api error: " + ex.getMessage());  } finally {    LOG.info("API Response {}", response);  }  return response;}

block()用于同步等待响应,这可能并不适合所有情况,你可能需要考虑subscribe()异步使用和处理响应。MhG28资讯网——每日最新资讯28at.com

(3) 异步发送请求:

有时我们不想等待响应,而是希望异步处理响应,这可以按如下方式完成:MhG28资讯网——每日最新资讯28at.com

import org.springframework.http.MediaType;import org.springframework.web.reactive.function.BodyInserters;import org.springframework.web.reactive.function.client.WebClient;import reactor.core.publisher.Mono;public static Mono<String> makePostRequestAsync(String url, String postData) {    WebClient webClient = WebClient.builder().build();    return webClient.post()            .uri(url)            .contentType(MediaType.APPLICATION_FORM_URLENCODED)            .body(BodyInserters.fromFormData("data", postData))            .retrieve()            .bodyToMono(String.class);}

要使用此函数,只需传入要向其发送 POST 请求的 URL 以及要在请求正文中以 URL 编码字符串形式发送的数据。关注工众号:码猿技术专栏,回复关键词:1111 获取阿里内部Java性能调优手册!该函数将返回来自服务器的响应,或者如果请求由于任何原因失败,则返回一条错误消息。MhG28资讯网——每日最新资讯28at.com

请注意,在此示例中,WebClient是使用默认配置构建的。你可能需要根据不同要求进行不同的配置。MhG28资讯网——每日最新资讯28at.com

另请注意,block()用于同步等待响应,这可能并不适合所有情况。你可能需要考虑subscribe()异步使用和处理响应。MhG28资讯网——每日最新资讯28at.com

要使用响应,您可以订阅Mono并异步处理响应。下面是一个例子:MhG28资讯网——每日最新资讯28at.com

makePostRequestAsync( "https://example.com/api" , "param1=value1¶m2=value2" ) .subscribe(response -> {     // 处理响应    System.out.println ( response ); }, error -> {     / / 处理错误    System.err.println ( error .getMessage ());         });

subscribe()用于异步处理响应,你可以提供两个 lambda 表达式作为 subscribe() 的参数。如果请求成功并收到响应作为参数,则执行第一个 lambda 表达式;如果请求失败并收到错误作为参数,则执行第二个 lambda 表达式。MhG28资讯网——每日最新资讯28at.com

(4) 处理4XX和5XX错误:

import org.springframework.http.HttpStatus;import org.springframework.http.MediaType;import org.springframework.web.reactive.function.BodyInserters;import org.springframework.web.reactive.function.client.WebClient;import reactor.core.publisher.Mono;public static Mono<String> makePostRequestAsync(String url, String postData) {    WebClient webClient = WebClient.builder()            .baseUrl(url)            .build();    return webClient.post()            .uri("/")            .contentType(MediaType.APPLICATION_FORM_URLENCODED)            .body(BodyInserters.fromFormData("data", postData))            .retrieve()            .onStatus(HttpStatus::is4xxClientError, clientResponse -> Mono.error(new RuntimeException("Client error")))            .onStatus(HttpStatus::is5xxServerError, clientResponse -> Mono.error(new RuntimeException("Server error")))            .bodyToMono(String.class);}

在此示例中,该onStatus()方法被调用两次,一次针对 4xx 客户端错误,一次针对 5xx 服务器错误。onStatus() 每次调用都采用两个参数:MhG28资讯网——每日最新资讯28at.com

  • aPredicate确定错误状态代码是否与条件匹配
  • aFunction用于返回Mono,即要传播到订阅者的错误信息。

如果状态代码与条件匹配,Mono则会发出相应的状态代码,并且Mono链会因错误而终止。在此示例中,Mono 将发出一条 RuntimeException 错误消息,指示该错误是客户端错误还是服务器错误。MhG28资讯网——每日最新资讯28at.com

(5) 根据错误状态采取行动:

要根据Mono的subscribe()方法中的错误采取操作,可以在subscribe函数中处理响应的lambda表达式之后添加另一个lambda表达。如果在处理Monumber的过程中出现错误,则执行第二个lambda表达式。MhG28资讯网——每日最新资讯28at.com

下面是如何使用makePostRequestAsync函数和处理subscribe方法中的错误的更新示例:MhG28资讯网——每日最新资讯28at.com

makePostRequestAsync("https://example.com/api", "param1=value1¶m2=value2").subscribe(response -> {    // handle the response    System.out.println(response);}, error -> {    // handle the error    System.err.println("An error occurred: " + error.getMessage());    if (error instanceof WebClientResponseException) {        WebClientResponseException webClientResponseException = (WebClientResponseException) error;        int statusCode = webClientResponseException.getStatusCode().value();        String statusText = webClientResponseException.getStatusText();        System.err.println("Error status code: " + statusCode);        System.err.println("Error status text: " + statusText);    }});

subscribe方法中的第二个lambda表达式检查错误是否是WebClientResponseException的实例,这是WebClient在服务器有错误响应时抛出的特定类型的异常。如果它是WebClientResponseException的实例,则代码将从异常中提取状态代码和状态文本,并将它们记录到日志中。MhG28资讯网——每日最新资讯28at.com

还可以根据发生的特定错误在此lambda表达式中添加其他错误处理逻辑。例如,你可以重试请求、回退到默认值或以特定方式记录错误。MhG28资讯网——每日最新资讯28at.com

(6) 处理成功响应和错误的完整代码:

responseMono.subscribe(response -> {  // handle the response  LOG.info("SUCCESS API Response {}", response);},error -> {  // handle the error  LOG.error("An error occurred: {}", error.getMessage());  LOG.error("error class: {}", error.getClass());  // Errors / Exceptions from Server  if (error instanceof WebClientResponseException) {    WebClientResponseException webClientResponseException =        (WebClientResponseException) error;    int statusCode = webClientResponseException.getStatusCode().value();    String statusText = webClientResponseException.getStatusText();    LOG.info("Error status code: {}", statusCode);    LOG.info("Error status text: {}", statusText);    if (statusCode >= 400 && statusCode < 500) {      LOG.info(          "Error Response body {}", webClientResponseException.getResponseBodyAsString());    }    Throwable cause = webClientResponseException.getCause();    LOG.error("webClientResponseException");    if (null != cause) {      LOG.info("Cause {}", cause.getClass());      if (cause instanceof ReadTimeoutException) {        LOG.error("ReadTimeout Exception");      }      if (cause instanceof TimeoutException) {        LOG.error("Timeout Exception");      }    }  }  // Client errors i.e. Timeouts etc -   if (error instanceof WebClientRequestException) {    LOG.error("webClientRequestException");    WebClientRequestException webClientRequestException =        (WebClientRequestException) error;    Throwable cause = webClientRequestException.getCause();    if (null != cause) {      LOG.info("Cause {}", cause.getClass());      if (cause instanceof ReadTimeoutException) {        LOG.error("ReadTimeout Exception");      }            if (cause instanceof ConnectTimeoutException) {        LOG.error("Connect Timeout Exception");      }    }  }});

超时

我们可以在每个请求中设置超时,如下所示:MhG28资讯网——每日最新资讯28at.com

return webClient    .method(this.httpMethod)    .uri(this.uri)    .headers(httpHeaders -> httpHeaders.addAll(additionalHeaders))    .bodyValue(this.requestEntity)    .retrieve()    .bodyToMono(responseType)    .timeout(Duration.ofMillis(readTimeout))  // request timeout for this request    .block();

但是,我们无法在每个请求中设置连接超时,这是WebClient 的属性,只能设置一次。如果需要,我们始终可以使用新的连接超时值创建一个新的 Web 客户端实例。MhG28资讯网——每日最新资讯28at.com

连接超时、读取超时和请求超时的区别如下:MhG28资讯网——每日最新资讯28at.com

图片图片MhG28资讯网——每日最新资讯28at.com

结论

由于 RestTemplace 已弃用,开发人员应开始使用 WebClient 进行 REST 调用,非阻塞 I/O 调用肯定会提高应用程序性能。它不仅提供了许多其他令人兴奋的功能,例如改进的错误处理和对流的支持,而且如果需要,它还可以在阻塞模式下使用来模拟 RestTemplate 行为。MhG28资讯网——每日最新资讯28at.com

本文链接:http://www.28at.com/showinfo-26-12765-0.html别再使用 RestTemplate了,来了解一下官方推荐的 WebClient !

声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com

上一篇: 使用Optional优雅避免空指针异常

下一篇: Promise 和 Async/Await的区别

标签:
  • 热门焦点
  • K60 Pro官方停产 第三方瞬间涨价

    虽然没有官方宣布,但Redmi的一些高管也已经透露了,Redmi K60 Pro已经停产且不会补货,这一切都是为了即将到来的K60 Ultra铺路,属于厂家的正常操作。但有意思的是该机在停产之后
  • 一加Ace2 Pro真机揭晓 钛空灰配色质感拉满

    终于,在经过了几波预热之后,一加Ace2 Pro的外观真机图在网上出现了。还是博主数码闲聊站曝光的,这次的外观设计还是延续了一加11的方案,只是细节上有了调整,例如新加入了钛空灰
  • 三言两语说透设计模式的艺术-单例模式

    写在前面单例模式是一种常用的软件设计模式,它所创建的对象只有一个实例,且该实例易于被外界访问。单例对象由于只有一个实例,所以它可以方便地被系统中的其他对象共享,从而减少
  • 中国家电海外掘金正当时|出海专题

    作者|吴南南编辑|胡展嘉运营|陈佳慧出品|零态LT(ID:LingTai_LT)2023年,出海市场战况空前,中国创业者在海外纷纷摩拳擦掌,以期能够把中国的商业模式、创业理念、战略打法输出海外,他们依
  • 腾讯盖楼,字节拆墙

    来源 | 光子星球撰文 | 吴坤谚编辑 | 吴先之&ldquo;想重温暴刷深渊、30+技能搭配暴搓到爽的游戏体验吗?一起上晶核,即刻暴打!&rdquo;曾凭借直播腾讯旗下代理格斗游戏《DNF》一
  • 三星Galaxy Z Fold5官方渲染图曝光:13.4mm折叠厚度依旧感人

    据官方此前宣布,三星将于7月26日在韩国首尔举办Unpacked活动,届时将带来带来包括Galaxy Buds 3、Galaxy Watch 6、Galaxy Tab S9、Galaxy Z Flip 5、
  • iQOO Neo8 Pro抢先上架:首发天玑9200+ 安卓性能之王

    经过了一段时间的密集爆料,昨日iQOO官方如期对外宣布:将于5月23日推出全新的iQOO Neo8系列新品,官方称这是一款拥有旗舰级性能调校的作品。随着发布时
  • OPPO K11搭载长寿版100W超级闪充:26分钟充满100%

    据此前官方宣布,OPPO将于7月25日也就是今天下午14:30举办新品发布会,届时全新的OPPO K11将正式与大家见面,将主打旗舰影像,和同档位竞品相比,其最大的卖
  • 外交部:美方应停止在网络安全问题上不负责任地指责他国

      中国外交部今天(16日)举行例行记者会。会上,有记者问,美国情报官员称,他们正在阻拦来自中国以及其他国家的黑客获取相关科研成果。 中方对此有何评论?对此
Top