Spring5 of WebClient(转载)
前言
Spring5带来了新的响应式web开发框架WebFlux,同时,也引入了新的HttpClient框架WebClient。WebClient是Spring5中引入的执行 HTTP 请求的非阻塞、反应式客户端。它对同步和异步以及流方案都有很好的支持,WebClient发布后,RestTemplate将在将来版本中弃用,并且不会向前添加主要新功能。
WebClient与RestTemplate比较
WebClient是一个功能完善的Http请求客户端,与RestTemplate相比,WebClient支持以下内容:
- 非阻塞 I/O。
- 反应流背压(消费者消费负载过高时主动反馈生产者放慢生产速度的一种机制)。
- 具有高并发性,硬件资源消耗更少。
- 流畅的API设计。
- 同步和异步交互。
- 流式传输支持
HTTP底层库选择
Spring5的WebClient客户端和WebFlux服务器都依赖于相同的非阻塞编解码器来编码和解码请求和响应内容。默认底层使用Netty,内置支持Jetty反应性HttpClient实现。同时,也可以通过编码的方式实现ClientHttpConnector接口自定义新的底层库;如切换Jetty实现:
WebClient.builder()
.clientConnector(new JettyClientHttpConnector())
.build();
WebClient配置
基础配置
WebClient实例构造器可以设置一些基础的全局的web请求配置信息,比如默认的cookie、header、baseUrl等
WebClient.builder()
.defaultCookie("test","t1")
.defaultUriVariables(ImmutableMap.of("name","kl"))
.defaultHeader("header","kl")
.defaultHeaders(httpHeaders -> {
httpHeaders.add("header1","kl");
httpHeaders.add("header2","kl");
})
.defaultCookies(cookie ->{
cookie.add("cookie1","kl");
cookie.add("cookie2","kl");
})
.baseUrl("http://www.kailing.pub")
.build();
底层依赖Netty库配置
通过定制Netty底层库,可以配置SSl安全连接,以及请求超时,读写超时等。这里需要注意一个问题,默认的连接池最大连接500。获取连接超时默认是45000ms,你可以配置成动态的连接池,就可以突破这些默认配置,也可以根据业务自己制定。包括Netty的select线程和工作线程也都可以自己设置。
//配置动态连接池
//ConnectionProvider provider = ConnectionProvider.elastic("elastic pool");
//配置固定大小连接池,如最大连接数、连接获取超时、空闲连接死亡时间等
ConnectionProvider provider = ConnectionProvider.fixed("fixed", 45, 4000, Duration.ofSeconds(6));
HttpClient httpClient = HttpClient.create(provider)
.secure(sslContextSpec -> {
SslContextBuilder sslContextBuilder = SslContextBuilder.forClient()
.trustManager(new File("E://server.truststore"));
sslContextSpec.sslContext(sslContextBuilder);
}).tcpConfiguration(tcpClient -> {
//指定Netty的select 和 work线程数量
LoopResources loop = LoopResources.create("kl-event-loop", 1, 4, true);
return tcpClient.doOnConnected(connection -> {
//读写超时设置
connection.addHandlerLast(new ReadTimeoutHandler(10, TimeUnit.SECONDS))
.addHandlerLast(new WriteTimeoutHandler(10));
})
//连接超时设置
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 10000)
.option(ChannelOption.TCP_NODELAY, true)
.runOn(loop);
});
WebClient.builder()
.clientConnector(new ReactorClientHttpConnector(httpClient))
.build();
编解码配置
针对特定的数据交互格式,可以设置自定义编解码的模式,如下:
ExchangeStrategies strategies = ExchangeStrategies.builder()
.codecs(configurer -> {
configurer.customCodecs().decoder(new Jackson2JsonDecoder());
configurer.customCodecs().encoder(new Jackson2JsonEncoder());
})
.build();
WebClient.builder()
.exchangeStrategies(strategies)
.build();
get请求示例
uri构造时支持属性占位符,真实参数在入参时排序好就可以。同时可以通过accept设置媒体类型,以及编码。最终的结果值是通过Mono和Flux来接收的,在subscribe方法中订阅返回值。
WebClient client = WebClient.create("http://www.kailing.pub");
Mono<String> result = client.get()
.uri("/article/index/arcid/{id}.html", 256)
.acceptCharset(StandardCharsets.UTF_8)
.accept(MediaType.TEXT_HTML)
.retrieve()
.bodyToMono(String.class);
result.subscribe(System.err::println);
如果需要携带复杂的查询参数,可以通过UriComponentsBuilder构造出uri请求地址,如:
//定义query参数
MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
params.add("name", "kl");
params.add("age", "19");
//定义url参数
Map<String, Object> uriVariables = new HashMap<>();
uriVariables.put("id", 200);
String uri = UriComponentsBuilder.fromUriString("/article/index/arcid/{id}.html")
下载文件时,因为不清楚各种格式文件对应的MIME Type,可以设置accept为MediaType.ALL,然后使用Spring的Resource来接收数据即可,如:
WebClient.create("https://kk-open-public.oss-cn-shanghai.aliyuncs.com/xxx.xlsx")
.get()
.accept(MediaType.ALL)
.retrieve()
.bodyToMono(Resource.class)
.subscribe(resource -> {
try {
File file = new File("E://abcd.xlsx");
FileCopyUtils.copy(StreamUtils.copyToByteArray(resource.getInputStream()), file);
}catch (IOException ex){}
});
post请求示例
post请求示例演示了一个比较复杂的场景,同时包含表单参数和文件流数据。如果是普通post请求,直接通过bodyValue设置对象实例即可。不用FormInserter构造。
WebClient client = WebClient.create("http://www.kailing.pub");
FormInserter formInserter = fromMultipartData("name","kl")
.with("age",19)
.with("map",ImmutableMap.of("xx","xx"))
.with("file",new File("E://xxx.doc"));
Mono<String> result = client.post()
.uri("/article/index/arcid/{id}.html", 256)
.contentType(MediaType.APPLICATION_JSON)
.body(formInserter)
//.bodyValue(ImmutableMap.of("name","kl"))
.retrieve()
.bodyToMono(String.class);
result.subscribe(System.err::println);
同步返回结果
上面演示的都是异步的通过mono的subscribe订阅响应值。当然,如果你想同步阻塞获取结果,也可以通过.block()阻塞当前线程获取返回值。
WebClient client = WebClient.create("http://www.kailing.pub");
String result = client .get()
.uri("/article/index/arcid/{id}.html", 256)
.retrieve()
.bodyToMono(String.class)
.block();
System.err.println(result);
但是,如果需要进行多个调用,则更高效地方式是避免单独阻塞每个响应,而是等待组合结果,如:
WebClient client = WebClient.create("http://www.kailing.pub");
Mono<String> result1Mono = client .get()
.uri("/article/index/arcid/{id}.html", 255)
.retrieve()
.bodyToMono(String.class);
Mono<String> result2Mono = client .get()
.uri("/article/index/arcid/{id}.html", 254)
.retrieve()
.bodyToMono(String.class);
Map<String,String> map = Mono.zip(result1Mono, result2Mono, (result1, result2) -> {
Map<String, String> arrayList = new HashMap<>();
arrayList.put("result1", result1);
arrayList.put("result2", result2);
return arrayList;
}).block();
System.err.println(map.toString());
Filter过滤器
可以通过设置filter拦截器,统一修改拦截请求,比如认证的场景,如下示例,filter注册单个拦截器,filters可以注册多个拦截器,basicAuthentication是系统内置的用于basicAuth的拦截器,limitResponseSize是系统内置用于限制响值byte大小的拦截器
WebClient.builder()
.baseUrl("http://www.kailing.pub")
.filter((request, next) -> {
ClientRequest filtered = ClientRequest.from(request)
.header("foo", "bar")
.build();
return next.exchange(filtered);
})
.filters(filters ->{
filters.add(ExchangeFilterFunctions.basicAuthentication("username","password"));
filters.add(ExchangeFilterFunctions.limitResponseSize(800));
})
.build().get()
.uri("/article/index/arcid/{id}.html", 254)
.retrieve()
.bodyToMono(String.class)
.subscribe(System.err::println);
websocket支持
WebClient不支持websocket请求,请求websocket接口时需要使用WebSocketClient,如:
WebSocketClient client = new ReactorNettyWebSocketClient();
URI url = new URI("ws://localhost:8080/path");
client.execute(url, session ->
session.receive()
.doOnNext(System.out::println)
.then()
);
原文链接:https://segmentfault.com/a/1190000021133071
参考文档
https://blog.csdn.net/iteye_13139/article/details/82726588
Spring5 of WebClient(转载)的更多相关文章
- 转载 Silverlight实用窍门系列:1.Silverlight读取外部XML加载配置---(使用WebClient读取XAP包同目录下的XML文件))
转载:程兴亮文章,地址;http://www.cnblogs.com/chengxingliang/archive/2011/02/07/1949579.html 使用WebClient读取XAP包同 ...
- WebClient用法小结(转载)
如果只想从特定的URI请求文件,则使用WebClient,它是最简单的.NET类,它只用一两条命令执行基本操作,.NET FRAMEWORK目前支持以http:.https:.ftp:.和 file: ...
- 装饰者模式的学习(c#) EF SaveChanges() 报错(转载) C# 四舍五入 保留两位小数(转载) DataGridView样式生成器使用说明 MSSQL如何将查询结果拼接成字符串 快递查询 C# 通过smtp直接发送邮件 C# 带参访问接口,WebClient方式 C# 发送手机短信 文件 日志 写入 与读取
装饰者模式的学习(c#) 案例转自https://www.cnblogs.com/stonefeng/p/5679638.html //主体基类 using System;using System.C ...
- async/await 异步编程(转载)
转载地址:http://www.cnblogs.com/teroy/p/4015461.html 前言 最近在学习Web Api框架的时候接触到了async/await,这个特性是.NET 4.5引入 ...
- C# Windows Phone 8 WP8 开发,将WebClient的DownloadStringCompleted事件改成非同步的awiat方法。
原文:C# Windows Phone 8 WP8 开发,将WebClient的DownloadStringCompleted事件改成非同步的awiat方法. 一般我们在撰写Windows Phone ...
- 第三节:总结.Net下后端的几种请求方式(WebClient、WebRequest、HttpClient)
一. 前言 前端调用有Form表单提交,ajax提交,ajax一般是用Jquery的简化写法,在这里不再过多介绍: 后端调用大约有这些:WebCient.WebRequest.Httpclient.W ...
- 【转载】C#工具类:FTP操作辅助类FTPHelper
FTP是一个8位的客户端-服务器协议,能操作任何类型的文件而不需要进一步处理,就像MIME或Unicode一样.可以通过C#中的FtpWebRequest类.NetworkCredential类.We ...
- 《Spring5官方文档》新功能(4,3)
<Spring5官方文档>新功能 原文链接 译者:supriseli Spring框架的新功能 这一章主要提供Spring框架新的功能和变更. 升级到新版本的框架可以参考.Spring g ...
- 转载--无弹窗APT渗透实验
转载--无弹窗APT渗透实验 文章作者:亚信安全,转载自 FreeBuf.COM APT攻击方式花样繁多,我研究最近的流行的APT攻击方式,在本地搭建环境模拟一次简单的APT攻击,在模拟攻击过程中发现 ...
随机推荐
- jsp中连接数据库及实现增删改查
导入jdbc工具包 <%@page import="asp.engine.util.PageHelper"%><%@ page import="asp. ...
- STL初学
标准模板库STL初学 线性数据结构 vector 一维向量,相当于数组 list 链表 map 映射,提供(Key,Value)式操作,相当于哈希表 string char字符串 queue 队列,先 ...
- 浅析ReDoS
ReDoS(Regular expression Denial of Service) 正则表达式拒绝服务攻击.开发人员使用了正则表达式来对用户输入的数据进行有效性校验, 当编写校验的正则表达式存在缺 ...
- hashlib加密模块_python
一.hashlib模块 1.功能 主要用于字符串加密 2.常用方法 md5()/sha1():创建一个md5或者sha1加密模式的hash对象update(arg):用字符串参数来更新hash对象,如 ...
- 题解【洛谷P3478】[POI2008]STA-Station
题面 设\(dp_i\)表示以\(i\)为根节点时所有节点的深度之和. 首先以 \(1\) 为根求出所有点深度之和\(dp_1\),并预处理每个点的子树大小. 设 \(v\) 是 \(u\) 的孩子, ...
- js清空子节点
删除全部子节点 function removeAllChild(){ var div = document.getElementById("div1"); while(div.ha ...
- 快速将Navicat中数据表信息导出
1.使用navicat工具 2.新建查询 SELECT COLUMN_NAME 字段名, COLUMN_TYPE 数据类型, DATA_TYPE 字段类型, CHARACTER_MAXIMUM_L ...
- OERR: ORA-32004 "obsolete or deprecated parameter(s) specified for %s instance"
Oracle 11gR2通过Memory创建动态参数文件后,通过SPFILE启动,提示 ORA-32004: obsolete or deprecated parameter(s) specified ...
- sql语句代码规范
19年年底的时候领导一直强调代码规范化以前写代码的时候很随意后来越来越看自己写的代码难受逐渐的也像规范化走去,今天又学了一招记录分享一下 这张图就是以前写代码的时候正常情况很是杂乱无章 这张就是规范话 ...
- python 日志模块 日志格式
形如: formatter = logging.Formatter("%(asctime)s %(levelname)s %(message)s","%Y%b%d-%H: ...