Spring框架中使用WebClient发送请求

从 Spring 5 开始,Spring 中全面引入了 Reactive 响应式编程。而 WebClient 则是 Spring WebFlux 模块提供的一个非阻塞的基于响应式编程的进行 Http 请求的客户端工具。

由于 WebClient 的请求模式属于异步非阻塞,能够以少量固定的线程处理高并发的 HTTP 请求。因此,从 Spring 5 开始,HTTP 服务之间的通信我们就可以考虑使用 WebClient 来取代之前的 RestTemplate。

下面记录 WebClient 的基本使用方法,并记录如何通过 WebClient 发送 GET 和 POST 请求。

1.添加依赖

要使用 WebClient,首先需要在 Maven 项目中添加 Spring WebFlux 依赖:

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

对于 Gradle 项目:

implementation 'org.springframework.boot:spring-boot-starter-webflux'

2.创建 WebClient 实例

可以通过多种方式创建 WebClient 实例:

方式一:全局 WebClient Bean(推荐)

在 Spring 项目中,通常会通过定义一个 WebClient.Builder Bean,并在需要的地方注入。

@Configuration
public class WebClientConfig {
    @Bean
    public WebClient.Builder webClientBuilder() {
        return WebClient.builder();
    }
}

然后在服务中使用:

@Service
public class MyService {
    private final WebClient webClient;
    public MyService(WebClient.Builder webClientBuilder) {
        this.webClient = webClientBuilder.baseUrl("https://example.com").build();
    }
    public String getData() {
        return webClient.get()
                        .uri("/api/data")
                        .retrieve()
                        .bodyToMono(String.class)
                        .block(); // 这里使用 block() 表示阻塞操作
    }
}

方式二:使用静态创建方法

可以直接使用 WebClient.create() 创建客户端实例:

WebClient webClient = WebClient.create("https://example.com");

3.发送请求

3.1 发送 GET 请求

public String getData() {
    WebClient webClient = WebClient.create("https://jsonplaceholder.typicode.com");
    String response = webClient.get()
                               .uri("/posts/1")
                               .retrieve()
                               .bodyToMono(String.class) 
                               .block(); 
    return response;
}
  • retrieve():用于发出请求并获取响应。
  • bodyToMono(String.class):将响应体转换为Mono,Mono 表示一个异步的单值序列。
  • block():阻塞当前线程,直到请求完成并返回结果。

3.2 发送 POST 请求

下面是一个发送 POST 请求并传递 JSON 数据的例子:

public String postData() {
    WebClient webClient = WebClient.create("https://jsonplaceholder.typicode.com");
    String response = webClient.post()
                               .uri("/posts")
                               .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) 
                               .bodyValue("{ \"title\": \"foo\", \"body\": \"bar\", \"userId\": 1 }") 
                               .retrieve()
                               .bodyToMono(String.class)
                               .block();
    return response;
}
  • bodyValue():设置请求体的数据,可以传递字符串、对象、或者其他序列化格式。
  • block():同步等待请求完成。

3.3 异步请求

如果不想阻塞线程,可以使用 WebClient 的异步处理功能。例如,使用 subscribe() 来处理异步请求:

public void getDataAsync() {
    WebClient webClient = WebClient.create("https://jsonplaceholder.typicode.com");
    webClient.get()
             .uri("/posts/1")
             .retrieve()
             .bodyToMono(String.class)
             .subscribe(response -> {
                 System.out.println("异步响应: " + response);
             });
}

这里使用了 subscribe() 方法,它接受一个 Consumer 回调函数,当响应到达时触发这个回调函数。

4. 处理错误响应

通过 WebClient,可以使用 onStatus() 来处理特定的 HTTP 响应状态码:

public String getDataWithErrorHandling() {
    WebClient webClient = WebClient.create("https://jsonplaceholder.typicode.com");
    return webClient.get()
                    .uri("/posts/invalid") 
                    .retrieve()
                    .onStatus(HttpStatus::is4xxClientError, response -> {
                        return response.bodyToMono(String.class)
                                       .flatMap(errorBody -> Mono.error(new RuntimeException("4xx 错误: " + errorBody)));
                    })
                    .onStatus(HttpStatus::is5xxServerError, response -> {
                        return response.bodyToMono(String.class)
                                       .flatMap(errorBody -> Mono.error(new RuntimeException("5xx 错误: " + errorBody)));
                    })
                    .bodyToMono(String.class)
                    .block();
}

5. 超时配置

可以通过自定义 WebClient 的 HttpClient 来设置超时时间:

import reactor.netty.http.client.HttpClient;
import java.time.Duration;
HttpClient httpClient = HttpClient.create()
                                  .responseTimeout(Duration.ofSeconds(5)); // 设置响应超时
WebClient webClient = WebClient.builder()
                               .clientConnector(new ReactorClientHttpConnector(httpClient))
                               .build();

6. 文件上传

通过 WebClient 实现文件上传,可以使用 multipart/form-data 来传递文件:

import org.springframework.http.MediaType;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
public String uploadFile() {
    WebClient webClient = WebClient.create("https://example.com");
    Resource file = new FileSystemResource("/path/to/file.txt");
    return webClient.post()
                    .uri("/upload")
                    .contentType(MediaType.MULTIPART_FORM_DATA)
                    .bodyValue(file)
                    .retrieve()
                    .bodyToMono(String.class)
                    .block();
}

总结:

  • 同步调用: 可以使用 .block() 让 WebClient 的调用同步阻塞,方便传统开发者的过渡。
  • 异步调用: 通过 Mono 和Flux 支持异步和响应式的编程模型,非常适合处理大量并发请求。
  • 丰富的错误处理: 可以通过 onStatus() 针对不同的状态码进行错误处理。
  • 灵活性强: 可以自定义超时、拦截器、连接池等,适应各种复杂场景。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值