网站首页 > 技术文章 正文
WebClient是Spring5引入的,基于响应式编程实现的HTTP调用客户端。Spring官方推荐使用WebClient替代RestTemplate完成HTTP调用。因为WebClient是基于Reactor实现的,所以既可以支持阻塞调用也可以支持非阻塞调用,在高并发的场景下资源利用率更高。这也是官方推荐使用的重要原因之一。
如果大家不了解响应式编程,强烈建议可以先看一下我这篇文章,这样对本篇文章中的样例代码也会有些帮助。
如果在工程中想要使用WebClient,在Pom文件中加入如下依赖
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-webflux</artifactId>
</dependency>如果使用的是Gradle,则加入如下依赖
dependencies {
    compile 'org.springframework.boot:spring-boot-starter-webflux'
    }初始化WebClient
- 直接初始化,不加任何参数。
    WebClient client = WebClient.create();- 初始化时,提供一个默认的调用地址。
WebClient client = WebClient.create("http://localhost:8080");- 自定义参数初始化。
WebClient client = WebClient.builder()
    .baseUrl("http://localhost:8080")
    .defaultCookie("cookieKey", "cookieValue")
    .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
    .defaultUriVariables(Collections.singletonMap("url", "http://localhost:8080"))
    .build();- 修改默认的超时时间。
//通过HttpClient设置超时时间
HttpClient httpClient = HttpClient.create()
    //设置连接超时时间
    .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000)
    //设置响应超时时间
    .responseTimeout(Duration.ofMillis(5000))
    //分别设置读写超时时间
    .doOnConnected(conn -> conn.addHandlerLast(new          ReadTimeoutHandler(5000, TimeUnit.MILLISECONDS))     .addHandlerLast(new WriteTimeoutHandler(5000,TimeUnit.MILLISECONDS))); 
    
WebClient client = WebClient.builder()
.clientConnector(new ReactorClientHttpConnector(httpClient))
.build();发起Get请求
- 以阻塞的方式获取0或者1个返回结果,用Mono表示
//通过builder的方式初始化
WebClientWebClient webClient = WebClient.builder()        //配置头部信息  
.defaultHeader(HttpHeaders.ACCEPT_CHARSET, "UTF-8")
//定义过滤器        
.filter(ExchangeFilterFunctions.basicAuthentication("user","password"))
.filter((clientRequest, next) -> {           
        logger.info("Request: {} {}",clientRequest.method(),clientRequest.url());
clientRequest.headers()
        .forEach((name, values) -> values.forEach(value 
-> logger.info("{}={}", name, value)));
return next.exchange(clientRequest);
})
.build();
//发起GET请求
Mono<String> resp = webClient.get()
.uri("https://localhost:8080") 
//获取结果 
.retrieve()
//将结果转化为指定类型 
.bodyToMono(String.class);
//以阻塞的方式将结果打印出来
logger.info("result:{}",resp.block());- 以阻塞方式获取多个返回结果,用Flux表示
Flux<Book> bookFlux = WebClient.create()
                          .method(HttpMethod.GET)
                         .uri("http://localhost:8080/books")
                         .retrieve()
                         .bodyToFlux(Book.class);
 //通过阻塞的方式获取响应结果
 List<Book> books = bookFlux.collectList().block();
 //通过非阻塞的方式获取响应结果
 bookFlux.subscribe(book ->{System.out.print(book.getName());});- 通过非阻塞方式获取响应结果
Flux<Book> bookFlux = WebClient.create()
                          .method(HttpMethod.GET)
                         .uri("http://localhost:8080/books")
                         .retrieve()
                         .bodyToFlux(Book.class);
 //通过非阻塞的方式获取响应结果
 bookFlux.subscribe(book ->{System.out.print(book.getName());});- 通过占位符传参
Mono<String> mono = WebClient.create()
                    .method(HttpMethod.POST)
                  .uri("http://localhost:8080/book/{id}/{name}", "1", "java")
                  .retrieve()
                  .bodyToMono(String.class);
                  String result = mono.block();除了占位符传参,还可以通过map形式传参等等,这里不一一举例介绍了。
发起POST请求
- 发起POST请求,提交Form表单
MultiValueMap<String, String> formData = new 
LinkedMultiValueMap<>();
formData.add("name1","value1");
formData.add("name2","value2");
Mono<String> resp = WebClient.create().post()
                    .uri("http://localhost:8080/submit")            .contentType(MediaType.APPLICATION_FORM_URLENCODED)
                    .body(BodyInserters.fromFormData(formData))        .retrieve().bodyToMono(String.class);
                    logger.info("result:{}",resp.block());- 使用Raw Json的方式发起POST请求。
Mono<String> resp = WebClient.create().post()
                    .uri("http://localhost:8080/book/json")
                                                                    .contentType(MediaType.APPLICATION_JSON)
                                                                    .body(BodyInserters.fromValue("{\n" +                "    \"name\" : \"java\",\n" +                "    \"price\" : \"32.5\" \n" +                " }"))        .retrieve().bodyToMono(String.class);
logger.info("result:{}",resp.block());错误和异常处理
WebClient可以更优雅地处理错误和异常。
//创建WebClient
        WebClient webClient = WebClient.builder()
                .baseUrl("http://localhost:8080")
                .defaultHeader(HttpHeaders.CONTENT_TYPE, "application/json")
                .defaultHeader(HttpHeaders.ACCEPT_CHARSET, "UTF-8")
                .build();
        //发起Get请求
        WebClient.ResponseSpec responseSpec = webClient.method(HttpMethod.GET)
                .uri("/book/remark/{id}", "1")
                .retrieve();
        //根据状态码进行响应
        Mono<String> mono = responseSpec
                .onStatus(e -> e.is4xxClientError(),resp -> {
                    logger.error("error:{},msg:{}",resp.statusCode().value(),resp.statusCode().getReasonPhrase());
                    return Mono.error(new RuntimeException(resp.statusCode().value() + " : " + resp.statusCode().getReasonPhrase()));
                })
                .bodyToMono(String.class)
                .doOnError(WebClientResponseException.class, err -> {
                    logger.info("ERROR status:{},msg:{}",err.getRawStatusCode(),err.getResponseBodyAsString());
                    throw new RuntimeException(err.getMessage());
                })
                .onErrorReturn("fallback");
        String result = mono.block();
        logger.info("result:{}",result);
总结
以上是一些WebClient使用的小Demo,希望对那些想了解WebClient的同学有一些帮助。如果想深入了解,建议还是多看看官方文档。
猜你喜欢
- 2024-09-08 精讲RestTemplate第7篇-自定义请求失败异常处理
- 2024-09-08 java实现调用http请求的几种常见方式
- 2024-09-08 深度原理学习——白话TCP与HTTP的keep–alive机制
- 2024-09-08 Spring Boot外部接口调用:使用RestTemplate与WebClient操控HTTP
- 2024-09-08 Java服务优雅上下线(java项目如何上线)
- 2024-09-08 Spring 框架里的 HTTP 调用,RestTemplate 还是 WebClient
- 2024-09-08 微服务中如何使用RestTemplate优雅调用API(详细分析)
- 2024-09-08 真不是吹,Spring 里这款牛逼的网络工具库你可能没用过
- 2024-09-08 Java工具类封装微服务间HTTP通信(java md5工具类)
- 2024-09-08 5月29号软件资讯更新合集(软件九月)
- 最近发表
- 
- 聊一下 gRPC 的 C++ 异步编程_grpc 异步流模式
- [原创首发]安全日志管理中心实战(3)——开源NIDS之suricata部署
- 超详细手把手搭建在ubuntu系统的FFmpeg环境
- Nginx运维之路(Docker多段构建新版本并增加第三方模
- 92.1K小星星,一款开源免费的远程桌面,让你告别付费远程控制!
- Go 人脸识别教程_piwigo人脸识别
- 安卓手机安装Termux——搭建移动服务器
- ubuntu 安装开发环境(c/c++ 15)_ubuntu安装c++编译器
- Rust开发环境搭建指南:从安装到镜像配置的零坑实践
- Windows系统安装VirtualBox构造本地Linux开发环境
 
- 标签列表
- 
- cmd/c (90)
- c++中::是什么意思 (84)
- 标签用于 (71)
- 主键只能有一个吗 (77)
- c#console.writeline不显示 (95)
- pythoncase语句 (88)
- es6includes (74)
- sqlset (76)
- apt-getinstall-y (100)
- node_modules怎么生成 (87)
- chromepost (71)
- flexdirection (73)
- c++int转char (80)
- mysqlany_value (79)
- static函数和普通函数 (84)
- el-date-picker开始日期早于结束日期 (76)
- js判断是否是json字符串 (75)
- c语言min函数头文件 (77)
- asynccallback (87)
- localstorage.removeitem (77)
- vector线程安全吗 (73)
- java (73)
- js数组插入 (83)
- mac安装java (72)
- 无效的列索引 (74)
 
