Spring 的http请求调用:WebClient的用法

终于进入springboot了,老框架也不用维护了,开心

这里记录下 WebClient 的学习

  1. 介绍
    WebClient是从Spring WebFlux 5.0版本开始提供的一个非阻塞的基于响应式编程的进行Http请求的客户端工具。

  2. 进入正题,先是封装好的单例工具,本篇文章主要介绍我的踩坑经历,使用示例可以看最后的参考链接

pom

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-webflux</artifactId>
    </dependency>

util

public enum WebClientUtils {
  INSTANCE;

  public WebClient.Builder webClientBuilder =
      WebClient.builder()
          .defaultHeader(HttpHeaders.CONTENT_TYPE, "application/json")
          .defaultHeader("App-Locale", "chs")
          .defaultHeader(
              HttpHeaders.USER_AGENT,
              "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36");

/**
* 如果get的参数有数组请不要用这个方法;post只支持body json的这种
* 这里为了方便这样封装 ,headers是头,其实可以在post后面写的,但是不想用MultiValueMap再转,
* errorHandle是遇到错误的处理
* JsonUtils中的方法可以根据使用的JSON工具替换掉,如JSON,Mapper或者Gson中对应的方法
*/
  public <T, R> Mono<T> http(Map<String, String> headers,
      String url, R request, Class<T> cls, boolean isGet,
      Function<ClientResponse, Mono<? extends Throwable>> errorHandle) {

    if (!ObjectUtils.isEmpty(headers)) {
      headers.entrySet().stream().forEach(entry -> {
        webClientBuilder.defaultHeader(entry.getKey(), entry.getValue());
      });
    }

    Mono<T> result = null;

    WebClient.ResponseSpec responseSpec = null;

    if (isGet) {
      Map<String, String> params = null;

      String uri = url;

      if (!ObjectUtils.isEmpty(request)) {
        try {
          String requestStr = JsonUtils.beanToJson(request);
          params = JsonUtils.jsonToMap(requestStr);
        } catch (Exception e) {
          throw new ServiceException(JSON_MAPPER_ERROR);
        }

        Map<String, String> finalParams = params;

        uri = url + UriComponentsBuilder.newInstance()
            .queryParams(
                finalParams.entrySet().stream().filter(e -> !StringUtils.isEmpty(e.getValue()))
                    .collect(Collectors.toMap(Entry::getKey,
                        e -> Collections.singletonList(e.getValue()), (t1, t2) -> t2,
                        LinkedMultiValueMap::new)))
            .build().toString();
      }

      responseSpec = webClientBuilder.build().get().uri(uri).retrieve();
    } else {

      responseSpec =
          webClientBuilder.build()
              .post()
              .uri(url)
              .body(Mono.just(request), new ParameterizedTypeReference<R>() {
              })
              .retrieve();
    }

    result =
        responseSpec
            .onStatus(
                status -> status.value() != HttpStatus.OK.value(),
                ObjectUtils.isEmpty(errorHandle) ? (rs ->
                    rs.bodyToMono(String.class)
                        .map(body -> new ServiceException(ERROR_INFO.getCode(), body))
                ) : errorHandle)
            .bodyToMono(cls);

    return result;
  }

/**
* 表单
*/
  public <T> Mono<T> httpWithForm(
      String url, MultiValueMap request, Class<T> cls, Function<ClientResponse, Mono<? extends Throwable>> errorHandle) {
    Mono<T> result = null;
    WebClient.ResponseSpec responseSpec =
        webClientBuilder.build()
            .post()
            .uri(url)
            .contentType(MediaType.APPLICATION_FORM_URLENCODED)
            .body(BodyInserters.fromMultipartData(request))
            .retrieve();
    result =
        responseSpec
            .onStatus(
                status -> status.value() != HttpStatus.OK.value(),
                ObjectUtils.isEmpty(errorHandle) ? (rs ->
                    rs.bodyToMono(String.class)
                        .map(body -> new ServiceException(ERROR_INFO.getCode(), body))
                ) : errorHandle)
            .bodyToMono(cls);
  }
  1. 测试
    3.1 最简单的调用 block方法
private final static String SINA_URL = "http://hq.sinajs.cn";
    Mono<String> resultMono = WebClientUtils.INSTANCE.http(SINA_URL
        , RequestModel.builder().list("USDCNY").build()
        , String.class, true);

    String result = resultMono//不需要处理,可以直接resultMono.block();
        .retry(3)//重试次数
        .doOnRequest(num -> {//请求时处理
          System.out.println("reuqest:" + num);
        }).doOnError(d -> {//错误时处理
          System.out.println("error");
        }).doOnNext(d -> {//成功时处理
          System.out.println("success");
        }).block();

    System.out.println(result);

3.2 最简单的方法曝露,注意swagger官方还不支持(不过民间还是有对策的~)

 		@PostMapping("/test")
        Mono<String> test() {
                return resultMono;
        }

3.3 subscribe

result.subscribe(e -> {
      log.info("-------- test");
 });
 //哦,你会发现怎么log没有出来,那是因为subscribe还没跑,jvm就关了。。。这时候需要:
 TimeUnit.SECONDS.sleep(5);//到底睡多久,能不能动态,不好意思,我没找到答案,目前我是用CountDownLatch,但是报错的话,有问题,不知道怎么处理(和全局异常捕获流程上有冲突),放弃

3.4 多个不同返回值
同时发出多个请求,返回值Mono中泛型不一样的话:这个我是这么用的(官方的我也没找到,只能说瞎琢磨了)

Consumer c1 =  e -> {log.info("-------- c1");};
Consumer c2 =  e -> {log.info("-------- c2");};
Flux.merge(resultMono1,resultMono2).toStream().parallel().forEach(r -> {
	if(r instanceof String){
		c1.accept(r)
	}else{
	}
});

3.5 取消请求

Disposable disposable1 = result.subscribe(e -> {
      log.info("-------- test");
 });

disposable1.dispose();

参考:https://www.zifangsky.cn/1343.html

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Boot中进行高效的HTTP调用,并携带Cookie和请求头参数,您可以使用RestTemplate或WebClient。这两个类都是Spring提供的用于进行HTTP调用的工具。 1. 使用RestTemplate进行HTTP调用: 首先,确保在您的项目中包含以下Maven依赖项: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web-services</artifactId> </dependency> ``` 然后,在您的代码中使用RestTemplate进行HTTP调用: ```java import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.ResponseEntity; import org.springframework.util.MultiValueMap; import org.springframework.web.client.RestTemplate; public class HttpClientUtil { public static ResponseEntity<String> sendRequest(String url, HttpMethod method, MultiValueMap<String, String> headers, String cookie) { RestTemplate restTemplate = new RestTemplate(); HttpHeaders httpHeaders = new HttpHeaders(); httpHeaders.addAll(headers); httpHeaders.add("Cookie", cookie); HttpEntity<String> httpEntity = new HttpEntity<>(httpHeaders); return restTemplate.exchange(url, method, httpEntity, String.class); } } ``` 在上面的示例中,`sendRequest` 方法接受URL、HTTP方法、请求头参数和Cookie作为参数,并返回一个包含响应的 ResponseEntity 对象。 2. 使用WebClient进行HTTP调用: 首先,确保在您的项目中包含以下Maven依赖项: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-webflux</artifactId> </dependency> ``` 然后,在您的代码中使用WebClient进行HTTP调用: ```java import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.MediaType; import org.springframework.web.reactive.function.client.WebClient; import reactor.core.publisher.Mono; public class HttpClientUtil { public static Mono<String> sendRequest(String url, HttpMethod method, HttpHeaders headers, String cookie) { WebClient webClient = WebClient.builder() .baseUrl(url) .defaultHeaders(httpHeaders -> { httpHeaders.addAll(headers); httpHeaders.setContentType(MediaType.APPLICATION_JSON); httpHeaders.add("Cookie", cookie); }) .build(); return webClient.method(method) .retrieve() .bodyToMono(String.class); } } ``` 在上面的示例中,`sendRequest` 方法接受URL、HTTP方法、请求头参数和Cookie作为参数,并返回一个 Mono 对象,其中包含响应结果。 使用上述任一方法,您可以在Spring Boot应用程序中进行高效的HTTP调用,并携带Cookie和请求头参数。根据您的需求,您可以扩展这些示例以满足更复杂的需求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值