此版本仍在开发中,尚不被认为是稳定的。对于最新的稳定版本,请使用 Spring Framework 6.2.10! |
响应式核心
这spring-web
模块包含以下对响应式 Web 的基础支持
应用:
-
对于服务器请求处理,有两个级别的支持。
-
HttpHandler:HTTP 请求处理的基本合约 非阻塞 I/O 和反应流背压,以及用于 Reactor Netty 的适配器, Undertow、Tomcat、Jetty 和任何 Servlet 容器。
-
WebHandler
应用程序接口:稍高级别的通用 Web API 请求处理,在此基础上有具体的编程模型,例如 Commentted 构建控制器和功能端点。
-
-
对于客户端,有一个基本的
ClientHttpConnector
执行 HTTP 的合约 具有非阻塞 I/O 和响应式流背压的请求,以及 Reactor Netty、响应式 Jetty HttpClient 和 Apache HttpComponents 的适配器。 应用程序中使用的更高级别的 WebClient 建立在这个基本契约的基础上。 -
对于客户端和服务器,用于序列化的编解码器和 HTTP 请求和响应内容的反序列化。
HttpHandler
HttpHandler 是一个简单的合约,具有处理请求和响应的单一方法。是的 故意最小化,其主要和唯一目的是成为最小抽象 通过不同的 HTTP 服务器 API。
下表介绍了支持的服务器 API:
服务器名称 | 使用的服务器 API | 响应式流支持 |
---|---|---|
网 |
Netty API |
|
Undertow |
暗流 API |
spring-web:Undertow 到 Reactive Streams 桥接器 |
Tomcat |
Servlet 非阻塞 I/O;用于读写 ByteBuffers 的 Tomcat API 与 byte[] |
spring-web:Servlet 非阻塞 I/O 到 Reactive Streams 桥接器 |
Jetty |
Servlet 非阻塞 I/O;用于编写 ByteBuffers 的 Jetty API 与 byte[] |
spring-web:Servlet 非阻塞 I/O 到 Reactive Streams 桥接器 |
Servlet 容器 |
Servlet 非阻塞 I/O |
spring-web:Servlet 非阻塞 I/O 到 Reactive Streams 桥接器 |
下表描述了服务器依赖项(另请参阅支持的版本):
服务器名称 | 组 ID | 神器名称 |
---|---|---|
反应器网 |
io.projectreactor.netty |
反应器网 |
Undertow |
io.undertow |
暗拖核心 |
Tomcat |
org.apache.tomcat.embed |
tomcat-嵌入核心 |
Jetty |
org.eclipse.Jetty |
jetty-server, jetty-servlet |
下面的代码片段显示了使用HttpHandler
适配器与每个服务器 API 一起使用:
反应器网
-
Java
-
Kotlin
HttpHandler handler = ...
ReactorHttpHandlerAdapter adapter = new ReactorHttpHandlerAdapter(handler);
HttpServer.create().host(host).port(port).handle(adapter).bindNow();
val handler: HttpHandler = ...
val adapter = ReactorHttpHandlerAdapter(handler)
HttpServer.create().host(host).port(port).handle(adapter).bindNow()
Undertow
-
Java
-
Kotlin
HttpHandler handler = ...
UndertowHttpHandlerAdapter adapter = new UndertowHttpHandlerAdapter(handler);
Undertow server = Undertow.builder().addHttpListener(port, host).setHandler(adapter).build();
server.start();
val handler: HttpHandler = ...
val adapter = UndertowHttpHandlerAdapter(handler)
val server = Undertow.builder().addHttpListener(port, host).setHandler(adapter).build()
server.start()
Tomcat
-
Java
-
Kotlin
HttpHandler handler = ...
Servlet servlet = new TomcatHttpHandlerAdapter(handler);
Tomcat server = new Tomcat();
File base = new File(System.getProperty("java.io.tmpdir"));
Context rootContext = server.addContext("", base.getAbsolutePath());
Tomcat.addServlet(rootContext, "main", servlet);
rootContext.addServletMappingDecoded("/", "main");
server.setHost(host);
server.setPort(port);
server.start();
val handler: HttpHandler = ...
val servlet = TomcatHttpHandlerAdapter(handler)
val server = Tomcat()
val base = File(System.getProperty("java.io.tmpdir"))
val rootContext = server.addContext("", base.absolutePath)
Tomcat.addServlet(rootContext, "main", servlet)
rootContext.addServletMappingDecoded("/", "main")
server.host = host
server.setPort(port)
server.start()
Jetty
-
Java
-
Kotlin
HttpHandler handler = ...
Servlet servlet = new JettyHttpHandlerAdapter(handler);
Server server = new Server();
ServletContextHandler contextHandler = new ServletContextHandler(server, "");
contextHandler.addServlet(new ServletHolder(servlet), "/");
contextHandler.start();
ServerConnector connector = new ServerConnector(server);
connector.setHost(host);
connector.setPort(port);
server.addConnector(connector);
server.start();
val handler: HttpHandler = ...
val servlet = JettyHttpHandlerAdapter(handler)
val server = Server()
val contextHandler = ServletContextHandler(server, "")
contextHandler.addServlet(ServletHolder(servlet), "/")
contextHandler.start();
val connector = ServerConnector(server)
connector.host = host
connector.port = port
server.addConnector(connector)
server.start()
Servlet 容器
要作为 WAR 部署到任何 Servlet 容器,您可以扩展并包含AbstractReactiveWebInitializer
在战争中。该类包装了HttpHandler
跟ServletHttpHandlerAdapter
和寄存器
作为Servlet
.
WebHandler
应用程序接口
这org.springframework.web.server
包构建在HttpHandler
合同
提供通用 Web API,用于通过多个链处理请求WebExceptionHandler
倍数WebFilter
,并且单个WebHandler
元件。链条可以
与WebHttpHandlerBuilder
只需指向弹簧ApplicationContext
其中组件是自动检测的,和/或通过注册组件
与架构商。
而HttpHandler
有一个简单的目标,即抽象使用不同的 HTTP 服务器,WebHandler
API 旨在提供 Web 应用程序中常用的更广泛的功能集
如:
-
具有属性的用户会话。
-
请求属性。
-
解决
Locale
或Principal
对于请求。 -
访问解析和缓存的表单数据。
-
多部分数据的抽象。
-
以及更多..
特殊Beans
下表列出了以下组件:WebHttpHandlerBuilder
可以在
Spring ApplicationContext,或者可以直接向它注册:
豆子名称 | Beans | 计数 | 描述 |
---|---|---|---|
<任何> |
|
0..N |
提供对来自 |
<任何> |
|
0..N |
将拦截样式逻辑应用于筛选器链的其余部分之前和之后,以及
目标 |
|
|
1 |
请求的处理程序。 |
|
|
0..1 |
经理 |
|
|
0..1 |
用于访问 |
|
|
0..1 |
的解析器 |
|
|
0..1 |
用于处理转发的类型标头,通过提取和删除它们或仅删除它们。 默认情况下不使用。 |
表单数据
ServerWebExchange
公开了以下访问表单数据的方法:
-
Java
-
Kotlin
Mono<MultiValueMap<String, String>> getFormData();
suspend fun getFormData(): MultiValueMap<String, String>
这DefaultServerWebExchange
使用配置的HttpMessageReader
解析表单数据
(application/x-www-form-urlencoded
) 转换为MultiValueMap
.默认情况下,FormHttpMessageReader
配置为ServerCodecConfigurer
豆
(请参阅 Web 处理程序 API)。
多部分数据
ServerWebExchange
公开了以下用于访问多部分数据的方法:
-
Java
-
Kotlin
Mono<MultiValueMap<String, Part>> getMultipartData();
suspend fun getMultipartData(): MultiValueMap<String, Part>
这DefaultServerWebExchange
使用配置的HttpMessageReader<MultiValueMap<String, Part>>
解析multipart/form-data
,multipart/mixed
和multipart/related
内容转换为MultiValueMap
.
默认情况下,这是DefaultPartHttpMessageReader
,没有任何第三方
依赖。
或者,SynchronossPartHttpMessageReader
可以使用,它基于 Synchronoss NIO Multipart 库。
两者都是通过ServerCodecConfigurer
豆
(请参阅 Web 处理程序 API)。
要以流式方式解析多部分数据,您可以使用Flux<PartEvent>
从PartEventHttpMessageReader
而不是使用@RequestPart
,正如这意味着的那样Map
-like 访问按名称访问各个部分,因此需要完整解析多部分数据。相比之下,您可以使用@RequestBody
将内容解码为Flux<PartEvent>
没有 收集到MultiValueMap
.
请求头转发
当请求通过代理(例如负载均衡器)时,主机、端口和 方案可能会发生变化,这使得创建指向正确链接成为一项挑战 从客户端的角度来看,主机、端口和方案。
RFC 7239 定义了Forwarded
HTTP 标头
代理可以使用该信息来提供有关原始请求的信息。
非标准标头
还有其他非标准标头,包括X-Forwarded-Host
,X-Forwarded-Port
,X-Forwarded-Proto
,X-Forwarded-Ssl
和X-Forwarded-Prefix
.
X转发主机
虽然不是标准的,X-Forwarded-Host: <host>
是一个事实上的标准标头,用于将原始主机传达给
下游服务器。例如,如果请求example.com/resource
被发送到
将请求转发给localhost:8080/resource
,然后是X-Forwarded-Host: example.com
可以发送以通知服务器原始主机是example.com
.
X转发端口
虽然不是标准的,X-Forwarded-Port: <port>
是一个事实上的标准标头,用于
将原始端口通信到下游服务器。例如,如果请求example.com/resource
被发送到代理,代理将请求转发给localhost:8080/resource
,然后是X-Forwarded-Port: 443
可以发送
通知服务器原始端口是443
.
X-转发-原型
虽然不是标准的,X-Forwarded-Proto: (https|http)
是用于通信原始协议(例如,https / http)的事实上的标准标头
到下游服务器。例如,如果请求example.com/resource
被发送到
将请求转发给localhost:8080/resource
,然后是X-Forwarded-Proto: https
可以发送以通知服务器原始协议是https
.
X-转发-SSL
虽然不是标准的,X-Forwarded-Ssl: (on|off)
是一个事实上的标准标头,用于传达
原始协议(例如,HTTPS/HTTPS)发送到下游服务器。例如,如果请求example.com/resource
被发送到代理,代理将请求转发给localhost:8080/resource
,然后是X-Forwarded-Ssl: on
通知服务器
最初的协议是https
.
X转发前缀
虽然不是标准的,X-Forwarded-Prefix: <prefix>
是一个事实上的标准标头,用于将原始 URL 路径前缀传达给
下游服务器。
用途X-Forwarded-Prefix
可能因部署方案而异,并且需要灵活地
允许替换、删除或预置目标服务器的路径前缀。
方案 1:覆盖路径前缀
https://example.com/api/{path} -> http://localhost:8080/app1/{path}
前缀是捕获组之前路径的开头{path}
.对于代理,
前缀是/api
而对于服务器,前缀是/app1
.在这种情况下,代理
可以发送X-Forwarded-Prefix: /api
具有原始前缀/api
覆盖
服务器前缀/app1
.
方案 2:删除路径前缀
有时,应用程序可能希望删除前缀。例如,考虑 以下代理到服务器的映射:
https://app1.example.com/{path} -> http://localhost:8080/app1/{path} https://app2.example.com/{path} -> http://localhost:8080/app2/{path}
代理没有前缀,而应用程序app1
和app2
有路径前缀/app1
和/app2
分别。代理可以发送X-Forwarded-Prefix:
自
让空前缀覆盖服务器前缀/app1
和/app2
.
此部署方案的一个常见情况是按按 生产应用程序服务器,最好在每个应用程序中部署多个应用程序 服务器以降低费用。另一个原因是在同一台服务器上运行更多应用程序 以共享服务器运行所需的资源。 在这些方案中,应用程序需要一个非空上下文根,因为有多个 同一服务器上的应用程序。但是,这在 公共 API,应用程序可以使用提供好处的不同子域 如:
|
方案 3:插入路径前缀
在其他情况下,可能需要在前面添加前缀。例如,考虑 以下代理到服务器的映射:
https://example.com/api/app1/{path} -> http://localhost:8080/app1/{path}
在这种情况下,代理的前缀为/api/app1
服务器的前缀为/app1
.代理可以发送X-Forwarded-Prefix: /api/app1
具有原始前缀/api/app1
覆盖服务器前缀/app1
.
转发标头转换器
ForwardedHeaderTransformer
是修改主机、端口和方案的组件
请求,然后删除这些标头。如果您声明
它作为一个豆子,名字forwardedHeaderTransformer
,它将被检测和使用。
在 5.1 中ForwardedHeaderFilter 已被弃用并被ForwardedHeaderTransformer 因此,请求头转发可以更早地处理,在
交换被创建。如果仍然配置了过滤器,则它将从
过滤器,以及ForwardedHeaderTransformer 而是使用。 |
过滤器
在WebHandler
应用程序接口,您可以使用WebFilter
应用拦截样式
过滤器和目标处理链其余部分之前和之后的逻辑WebHandler
.使用 WebFlux Config 时,注册WebFilter
就这么简单
将其声明为 Spring bean 并(可选)通过使用@Order
上
bean 声明或通过实现Ordered
.
CORS
Spring WebFlux 通过对 CORS 配置的注释提供细粒度的支持
控制器。但是,当您将其与 Spring Security 一起使用时,我们建议依赖内置的CorsFilter
,必须在 Spring Security 的过滤器链之前订购。
请参阅有关 CORS 和CORSWebFilter
了解更多详情。
URL 处理程序
您可能希望控制器端点匹配 URL 路径中带有或不带有尾随斜杠的路由。
例如,“GET /home”和“GET /home/”都应由带有@GetMapping("/home")
.
将尾随斜杠变体添加到所有映射声明并不是处理此用例的最佳方法。
这UrlHandlerFilter
Web 过滤器就是为此目的而设计的。它可以配置为:
-
在收到带有尾随斜杠的 URL 时响应 HTTP 重定向状态,将浏览器发送到非尾随斜杠 URL 变体。
-
更改请求,使其就像发送请求时没有尾随斜杠一样,并继续处理请求。
以下是如何实例化和配置UrlHandlerFilter
对于博客应用程序:
-
Java
-
Kotlin
UrlHandlerFilter urlHandlerFilter = UrlHandlerFilter
// will HTTP 308 redirect "/blog/my-blog-post/" -> "/blog/my-blog-post"
.trailingSlashHandler("/blog/**").redirect(HttpStatus.PERMANENT_REDIRECT)
// will mutate the request to "/admin/user/account/" and make it as "/admin/user/account"
.trailingSlashHandler("/admin/**").mutateRequest()
.build();
val urlHandlerFilter = UrlHandlerFilter
// will HTTP 308 redirect "/blog/my-blog-post/" -> "/blog/my-blog-post"
.trailingSlashHandler("/blog/**").redirect(HttpStatus.PERMANENT_REDIRECT)
// will mutate the request to "/admin/user/account/" and make it as "/admin/user/account"
.trailingSlashHandler("/admin/**").mutateRequest()
.build()
异常
在WebHandler
应用程序接口,您可以使用WebExceptionHandler
处理
链中的例外WebFilter
实例和目标WebHandler
.使用 WebFlux Config 时,注册WebExceptionHandler
就像将其声明为
Spring bean 和(可选)通过使用@Order
在 bean 声明上或通过实现Ordered
.
下表描述了可用的WebExceptionHandler
实现:
异常处理程序 | 描述 |
---|---|
|
提供对类型 |
|
扩展 此处理程序在 WebFlux 配置中声明。 |
Codec
这spring-web
和spring-core
模块支持序列化和
通过非阻塞 I/O 将字节内容反序列化到更高级别对象或从更高级别对象反序列化
反应流背压。下面介绍了此支持:
-
HttpMessageReader
和HttpMessageWriter
是合同 对 HTTP 消息内容进行编码和解码。 -
一
Encoder
可以用EncoderHttpMessageWriter
使其适应在 Web 中使用 应用程序,而Decoder
可以用DecoderHttpMessageReader
. -
DataBuffer
摘要不同 字节缓冲区表示(例如,NettyByteBuf
,java.nio.ByteBuffer
等)并且是 所有编解码器的工作原理。请参阅 数据缓冲区和编解码器 有关此主题的更多信息,请参阅“Spring Core”部分。
这spring-core
模块提供byte[]
,ByteBuffer
,DataBuffer
,Resource
和String
编码器和解码器实现。这spring-web
模块提供 Jackson
JSON、Jackson Smile、JAXB2、协议缓冲区和其他编码器和解码器以及
表单数据、多部分内容、
服务器发送的事件等。
ClientCodecConfigurer
和ServerCodecConfigurer
通常用于配置和
自定义要在应用程序中使用的编解码器。请参阅有关配置 HTTP 消息编解码器的部分。
Jackson JSON
JSON 和二进制 JSON(微笑)是 当 Jackson 库存在时,两者都受支持。
这Jackson2Decoder
工作原理如下:
-
Jackson 的异步、非阻塞解析器用于聚合字节块流 到
TokenBuffer
的每个代表一个 JSON 对象。 -
每
TokenBuffer
传给Jackson的ObjectMapper
以创建更高级别的对象。 -
解码到单值发布者时(例如
Mono
),有一个TokenBuffer
. -
解码为多值发布者时(例如
Flux
),每个TokenBuffer
被传递给 这ObjectMapper
一旦收到完全格式对象的足够字节。这 输入内容可以是 JSON 数组,也可以是任何以行分隔的 JSON 格式,例如 NDJSON、 JSON 行或 JSON 文本序列。
这Jackson2Encoder
工作原理如下:
-
对于单个值发布商(例如
Mono
),只需通过ObjectMapper
. -
对于具有
application/json
,默认情况下使用Flux#collectToList()
,然后序列化生成的集合。 -
对于具有流媒体类型(如
application/x-ndjson
或application/stream+x-jackson-smile
、编码、写入和 使用行分隔的 JSON 格式单独刷新每个值。其他 流媒体类型可以注册到编码器。 -
对于 SSE,
Jackson2Encoder
每个事件调用,并刷新输出以确保 立即交货。
默认情况下,两者 |
表单数据
FormHttpMessageReader
和FormHttpMessageWriter
支持解码和编码application/x-www-form-urlencoded
内容。
在经常需要从多个地方访问表单内容的服务器端,ServerWebExchange
提供专用的getFormData()
解析内容的方法
通过FormHttpMessageReader
然后缓存结果以供重复访问。
请参阅WebHandler
应用程序接口部分。
一次getFormData()
使用时,无法再从
请求正文。因此,申请应通过ServerWebExchange
一致地访问缓存的表单数据,而不是从原始请求正文中读取。
多部分
MultipartHttpMessageReader
和MultipartHttpMessageWriter
支持解码和
对“multipart/form-data”、“multipart/mixed”和“multipart/related”内容进行编码。
挨次MultipartHttpMessageReader
委托给另一个HttpMessageReader
用于实际解析为Flux<Part>
然后简单地将这些部件收集到MultiValueMap
.
默认情况下,DefaultPartHttpMessageReader
,但这可以通过ServerCodecConfigurer
.
有关DefaultPartHttpMessageReader
,请参阅javadoc 的DefaultPartHttpMessageReader
.
在服务器端,可能需要从多个
地方ServerWebExchange
提供专用的getMultipartData()
解析的方法
内容通过MultipartHttpMessageReader
然后缓存结果以供重复访问。
请参阅WebHandler
应用程序接口部分。
一次getMultipartData()
使用时,无法再从
请求正文。因此,应用程序必须始终使用getMultipartData()
用于重复、类似地图的部件访问,或以其他方式依赖SynchronossPartHttpMessageReader
一次性访问Flux<Part>
.
协议缓冲区
ProtobufEncoder
和ProtobufDecoder
支持解码和编码“application/x-protobuf”、“application/octet-stream”
以及“application/vnd.google.protobuf”内容com.google.protobuf.Message
类型。它们还支持价值流
如果内容是沿内容类型(如“application/x-protobuf;delimited=true“)。
这需要“com.google.protobuf:protobuf-java”库,版本 3.29 及更高版本。
这ProtobufJsonDecoder
和ProtobufJsonEncoder
变体支持在 Protobuf 消息中读取和写入 JSON 文档。
它们需要“com.google.protobuf:protobuf-java-util”依赖项。请注意,JSON 变体不支持读取消息流,
请参阅javadoc 的ProtobufJsonDecoder
了解更多详情。
限制
Decoder
和HttpMessageReader
缓冲部分或全部输入的实现stream 可以配置为内存中缓冲的最大字节数限制。在某些情况下,缓冲是因为输入被聚合并表示为单个对象 — 例如,具有@RequestBody byte[]
,x-www-form-urlencoded
数据,依此类推。缓冲也可能发生在流式处理中,当拆分输入流——例如,分隔文本、JSON 对象流和等等。对于这些流式处理情况,限制适用于关联的字节数与流中的一个对象。
要配置缓冲区大小,您可以检查给定的Decoder
或HttpMessageReader
公开一个maxInMemorySize
属性,如果是这样,Javadoc 将包含有关默认值的详细信息 值。 在服务器端,ServerCodecConfigurer
提供了一个单一的地方设置所有编解码器,请参阅 HTTP 消息编解码器。在客户端,限制所有编解码器都可以在 WebClient.Builder 中更改。
对于多部分解析maxInMemorySize
属性限制非文件部件的大小。对于文件部件,它决定了部件的阈值被写入磁盘。对于写入磁盘的文件部件,还有一个额外的maxDiskUsagePerPart
属性来限制每个部分的磁盘空间量。还有 一个maxParts
属性来限制多部分请求中的部分总数。要在 WebFlux 中配置所有三个部分,您需要提供预配置的实例MultipartHttpMessageReader
自ServerCodecConfigurer
.
流
流式传输到 HTTP 响应时(例如text/event-stream
,application/x-ndjson
),定期发送数据非常重要,以便尽早可靠地检测断开连接的客户端。这样的发送可以是一个仅注释、空 SSE 事件或任何其他“无作”数据,这些数据将有效地充当心跳。
DataBuffer
DataBuffer
是 WebFlux 中字节缓冲区的表示形式。的 Spring Core 部分
此参考在数据缓冲区和编解码器部分中有更多相关内容。要理解的关键点是,在某些
像 Netty 这样的服务器,字节缓冲区被池化并对引用进行计数,并且必须释放
使用时以避免内存泄漏。
WebFlux 应用程序通常不需要关注此类问题,除非它们 直接使用或生成数据缓冲区,而不是依赖编解码器进行转换 以及来自更高级别的对象,或者除非他们选择创建自定义编解码器。对于这样的 情况请查看数据缓冲区和编解码器中的信息, 尤其是关于使用 DataBuffer 的部分。
Logging
DEBUG
Spring WebFlux 中的级别日志记录被设计为紧凑、最小和
人性化。它侧重于对
与其他仅在调试特定问题时有用的其他问题相比。
TRACE
关卡日志记录通常遵循与DEBUG
(例如,还
不应是消防水带),但可用于调试任何问题。此外,一些日志
消息可能会在TRACE
与DEBUG
.
良好的日志记录来自使用日志的经验。如果你发现任何可以 未达到既定目标,请告诉我们。
日志 ID
在 WebFlux 中,单个请求可以在多个线程上运行,并且线程 ID 对于关联属于特定请求的日志消息没有用处。这就是为什么 默认情况下,WebFlux 日志消息以特定于请求的 ID 为前缀。
在服务器端,日志 ID 存储在ServerWebExchange
属性
(LOG_ID_ATTRIBUTE
),
而基于该 ID 的完整格式化前缀可从ServerWebExchange#getLogPrefix()
.在WebClient
side,日志 ID 存储在ClientRequest
属性
(LOG_ID_ATTRIBUTE
)
,而完全格式化的前缀可从ClientRequest#logPrefix()
.
敏感数据
DEBUG
和TRACE
日志记录可以记录敏感信息。这就是为什么 form 参数和
默认情况下,标头是屏蔽的,您必须显式启用其完全日志记录。
以下示例显示了如何对服务器端请求执行此作:
-
Java
-
Kotlin
@Configuration
@EnableWebFlux
class MyConfig implements WebFluxConfigurer {
@Override
public void configureHttpMessageCodecs(ServerCodecConfigurer configurer) {
configurer.defaultCodecs().enableLoggingRequestDetails(true);
}
}
@Configuration
@EnableWebFlux
class MyConfig : WebFluxConfigurer {
override fun configureHttpMessageCodecs(configurer: ServerCodecConfigurer) {
configurer.defaultCodecs().enableLoggingRequestDetails(true)
}
}
以下示例演示如何对客户端请求执行此作:
-
Java
-
Kotlin
Consumer<ClientCodecConfigurer> consumer = configurer ->
configurer.defaultCodecs().enableLoggingRequestDetails(true);
WebClient webClient = WebClient.builder()
.exchangeStrategies(strategies -> strategies.codecs(consumer))
.build();
val consumer: (ClientCodecConfigurer) -> Unit = { configurer -> configurer.defaultCodecs().enableLoggingRequestDetails(true) }
val webClient = WebClient.builder()
.exchangeStrategies({ strategies -> strategies.codecs(consumer) })
.build()
自定义编解码器
应用程序可以注册自定义编解码器以支持其他媒体类型, 或默认编解码器不支持的特定行为。
以下示例演示如何对客户端请求执行此作:
-
Java
-
Kotlin
WebClient webClient = WebClient.builder()
.codecs(configurer -> {
CustomDecoder decoder = new CustomDecoder();
configurer.customCodecs().registerWithDefaultConfig(decoder);
})
.build();
val webClient = WebClient.builder()
.codecs({ configurer ->
val decoder = CustomDecoder()
configurer.customCodecs().registerWithDefaultConfig(decoder)
})
.build()