此版本仍在开发中,尚不被认为是稳定的。对于最新的稳定版本,请使用 Spring Framework 6.2.10spring-doc.cadn.net.cn

响应式核心

spring-web模块包含以下对响应式 Web 的基础支持 应用:spring-doc.cadn.net.cn

HttpHandler

HttpHandler 是一个简单的合约,具有处理请求和响应的单一方法。是的 故意最小化,其主要和唯一目的是成为最小抽象 通过不同的 HTTP 服务器 API。spring-doc.cadn.net.cn

下表介绍了支持的服务器 API:spring-doc.cadn.net.cn

服务器名称 使用的服务器 API 响应式流支持

spring-doc.cadn.net.cn

Netty APIspring-doc.cadn.net.cn

反应器网spring-doc.cadn.net.cn

Undertowspring-doc.cadn.net.cn

暗流 APIspring-doc.cadn.net.cn

spring-web:Undertow 到 Reactive Streams 桥接器spring-doc.cadn.net.cn

Tomcatspring-doc.cadn.net.cn

Servlet 非阻塞 I/O;用于读写 ByteBuffers 的 Tomcat API 与 byte[]spring-doc.cadn.net.cn

spring-web:Servlet 非阻塞 I/O 到 Reactive Streams 桥接器spring-doc.cadn.net.cn

Jettyspring-doc.cadn.net.cn

Servlet 非阻塞 I/O;用于编写 ByteBuffers 的 Jetty API 与 byte[]spring-doc.cadn.net.cn

spring-web:Servlet 非阻塞 I/O 到 Reactive Streams 桥接器spring-doc.cadn.net.cn

Servlet 容器spring-doc.cadn.net.cn

Servlet 非阻塞 I/Ospring-doc.cadn.net.cn

spring-web:Servlet 非阻塞 I/O 到 Reactive Streams 桥接器spring-doc.cadn.net.cn

下表描述了服务器依赖项(另请参阅支持的版本):spring-doc.cadn.net.cn

服务器名称 组 ID 神器名称

反应器网spring-doc.cadn.net.cn

io.projectreactor.nettyspring-doc.cadn.net.cn

反应器网spring-doc.cadn.net.cn

Undertowspring-doc.cadn.net.cn

io.undertowspring-doc.cadn.net.cn

暗拖核心spring-doc.cadn.net.cn

Tomcatspring-doc.cadn.net.cn

org.apache.tomcat.embedspring-doc.cadn.net.cn

tomcat-嵌入核心spring-doc.cadn.net.cn

Jettyspring-doc.cadn.net.cn

org.eclipse.Jettyspring-doc.cadn.net.cn

jetty-server, jetty-servletspring-doc.cadn.net.cn

下面的代码片段显示了使用HttpHandler适配器与每个服务器 API 一起使用:spring-doc.cadn.net.cn

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()
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()
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()
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 容器spring-doc.cadn.net.cn

要作为 WAR 部署到任何 Servlet 容器,您可以扩展并包含AbstractReactiveWebInitializer在战争中。该类包装了HttpHandlerServletHttpHandlerAdapter和寄存器 作为Servlet.spring-doc.cadn.net.cn

WebHandler应用程序接口

org.springframework.web.server包构建在HttpHandler合同 提供通用 Web API,用于通过多个链处理请求WebExceptionHandler倍数WebFilter,并且单个WebHandler元件。链条可以 与WebHttpHandlerBuilder只需指向弹簧ApplicationContext其中组件是自动检测的,和/或通过注册组件 与架构商。spring-doc.cadn.net.cn

HttpHandler有一个简单的目标,即抽象使用不同的 HTTP 服务器,WebHandlerAPI 旨在提供 Web 应用程序中常用的更广泛的功能集 如:spring-doc.cadn.net.cn

特殊Beans

下表列出了以下组件:WebHttpHandlerBuilder可以在 Spring ApplicationContext,或者可以直接向它注册:spring-doc.cadn.net.cn

豆子名称 Beans 计数 描述

<任何>spring-doc.cadn.net.cn

WebExceptionHandlerspring-doc.cadn.net.cn

0..Nspring-doc.cadn.net.cn

提供对来自WebFilter实例和目标WebHandler.有关更多详细信息,请参阅例外。spring-doc.cadn.net.cn

<任何>spring-doc.cadn.net.cn

WebFilterspring-doc.cadn.net.cn

0..Nspring-doc.cadn.net.cn

将拦截样式逻辑应用于筛选器链的其余部分之前和之后,以及 目标WebHandler.有关更多详细信息,请参阅过滤器spring-doc.cadn.net.cn

webHandlerspring-doc.cadn.net.cn

WebHandlerspring-doc.cadn.net.cn

1spring-doc.cadn.net.cn

请求的处理程序。spring-doc.cadn.net.cn

webSessionManagerspring-doc.cadn.net.cn

WebSessionManagerspring-doc.cadn.net.cn

0..1spring-doc.cadn.net.cn

经理WebSession通过ServerWebExchange.DefaultWebSessionManager默认情况下。spring-doc.cadn.net.cn

serverCodecConfigurerspring-doc.cadn.net.cn

ServerCodecConfigurerspring-doc.cadn.net.cn

0..1spring-doc.cadn.net.cn

用于访问HttpMessageReader用于解析表单数据和多部分数据的实例,即 通过方法公开ServerWebExchange.ServerCodecConfigurer.create()默认情况下。spring-doc.cadn.net.cn

localeContextResolverspring-doc.cadn.net.cn

LocaleContextResolverspring-doc.cadn.net.cn

0..1spring-doc.cadn.net.cn

的解析器LocaleContext通过ServerWebExchange.AcceptHeaderLocaleContextResolver默认情况下。spring-doc.cadn.net.cn

forwardedHeaderTransformerspring-doc.cadn.net.cn

ForwardedHeaderTransformerspring-doc.cadn.net.cn

0..1spring-doc.cadn.net.cn

用于处理转发的类型标头,通过提取和删除它们或仅删除它们。 默认情况下不使用。spring-doc.cadn.net.cn

表单数据

ServerWebExchange公开了以下访问表单数据的方法:spring-doc.cadn.net.cn

Mono<MultiValueMap<String, String>> getFormData();
suspend fun getFormData(): MultiValueMap<String, String>

DefaultServerWebExchange使用配置的HttpMessageReader解析表单数据 (application/x-www-form-urlencoded) 转换为MultiValueMap.默认情况下,FormHttpMessageReader配置为ServerCodecConfigurer豆 (请参阅 Web 处理程序 API)。spring-doc.cadn.net.cn

多部分数据

ServerWebExchange公开了以下用于访问多部分数据的方法:spring-doc.cadn.net.cn

Mono<MultiValueMap<String, Part>> getMultipartData();
suspend fun getMultipartData(): MultiValueMap<String, Part>

DefaultServerWebExchange使用配置的HttpMessageReader<MultiValueMap<String, Part>>解析multipart/form-data,multipart/mixedmultipart/related内容转换为MultiValueMap. 默认情况下,这是DefaultPartHttpMessageReader,没有任何第三方 依赖。 或者,SynchronossPartHttpMessageReader可以使用,它基于 Synchronoss NIO Multipart 库。 两者都是通过ServerCodecConfigurer豆 (请参阅 Web 处理程序 API)。spring-doc.cadn.net.cn

要以流式方式解析多部分数据,您可以使用Flux<PartEvent>PartEventHttpMessageReader而不是使用@RequestPart,正如这意味着的那样Map-like 访问按名称访问各个部分,因此需要完整解析多部分数据。相比之下,您可以使用@RequestBody将内容解码为Flux<PartEvent>没有 收集到MultiValueMap.spring-doc.cadn.net.cn

请求头转发

当请求通过代理(例如负载均衡器)时,主机、端口和 方案可能会发生变化,这使得创建指向正确链接成为一项挑战 从客户端的角度来看,主机、端口和方案。spring-doc.cadn.net.cn

RFC 7239 定义了ForwardedHTTP 标头 代理可以使用该信息来提供有关原始请求的信息。spring-doc.cadn.net.cn

非标准标头

还有其他非标准标头,包括X-Forwarded-Host,X-Forwarded-Port,X-Forwarded-Proto,X-Forwarded-SslX-Forwarded-Prefix.spring-doc.cadn.net.cn

X转发主机

虽然不是标准的,X-Forwarded-Host: <host>是一个事实上的标准标头,用于将原始主机传达给 下游服务器。例如,如果请求example.com/resource被发送到 将请求转发给localhost:8080/resource,然后是X-Forwarded-Host: example.com可以发送以通知服务器原始主机是example.com.spring-doc.cadn.net.cn

X转发端口

虽然不是标准的,X-Forwarded-Port: <port>是一个事实上的标准标头,用于 将原始端口通信到下游服务器。例如,如果请求example.com/resource被发送到代理,代理将请求转发给localhost:8080/resource,然后是X-Forwarded-Port: 443可以发送 通知服务器原始端口是443.spring-doc.cadn.net.cn

X-转发-原型

虽然不是标准的,X-Forwarded-Proto: (https|http)是用于通信原始协议(例如,https / http)的事实上的标准标头 到下游服务器。例如,如果请求example.com/resource被发送到 将请求转发给localhost:8080/resource,然后是X-Forwarded-Proto: https可以发送以通知服务器原始协议是https.spring-doc.cadn.net.cn

X-转发-SSL

虽然不是标准的,X-Forwarded-Ssl: (on|off)是一个事实上的标准标头,用于传达 原始协议(例如,HTTPS/HTTPS)发送到下游服务器。例如,如果请求example.com/resource被发送到代理,代理将请求转发给localhost:8080/resource,然后是X-Forwarded-Ssl: on通知服务器 最初的协议是https.spring-doc.cadn.net.cn

X转发前缀

虽然不是标准的,X-Forwarded-Prefix: <prefix>是一个事实上的标准标头,用于将原始 URL 路径前缀传达给 下游服务器。spring-doc.cadn.net.cn

用途X-Forwarded-Prefix可能因部署方案而异,并且需要灵活地 允许替换、删除或预置目标服务器的路径前缀。spring-doc.cadn.net.cn

方案 1:覆盖路径前缀spring-doc.cadn.net.cn

https://example.com/api/{path} -> http://localhost:8080/app1/{path}

前缀是捕获组之前路径的开头{path}.对于代理, 前缀是/api而对于服务器,前缀是/app1.在这种情况下,代理 可以发送X-Forwarded-Prefix: /api具有原始前缀/api覆盖 服务器前缀/app1.spring-doc.cadn.net.cn

方案 2:删除路径前缀spring-doc.cadn.net.cn

有时,应用程序可能希望删除前缀。例如,考虑 以下代理到服务器的映射:spring-doc.cadn.net.cn

https://app1.example.com/{path} -> http://localhost:8080/app1/{path}
https://app2.example.com/{path} -> http://localhost:8080/app2/{path}

代理没有前缀,而应用程序app1app2有路径前缀/app1/app2分别。代理可以发送X-Forwarded-Prefix: 自 让空前缀覆盖服务器前缀/app1/app2.spring-doc.cadn.net.cn

此部署方案的一个常见情况是按按 生产应用程序服务器,最好在每个应用程序中部署多个应用程序 服务器以降低费用。另一个原因是在同一台服务器上运行更多应用程序 以共享服务器运行所需的资源。spring-doc.cadn.net.cn

在这些方案中,应用程序需要一个非空上下文根,因为有多个 同一服务器上的应用程序。但是,这在 公共 API,应用程序可以使用提供好处的不同子域 如:spring-doc.cadn.net.cn

方案 3:插入路径前缀spring-doc.cadn.net.cn

在其他情况下,可能需要在前面添加前缀。例如,考虑 以下代理到服务器的映射:spring-doc.cadn.net.cn

https://example.com/api/app1/{path} -> http://localhost:8080/app1/{path}

在这种情况下,代理的前缀为/api/app1服务器的前缀为/app1.代理可以发送X-Forwarded-Prefix: /api/app1具有原始前缀/api/app1覆盖服务器前缀/app1.spring-doc.cadn.net.cn

转发标头转换器

ForwardedHeaderTransformer是修改主机、端口和方案的组件 请求,然后删除这些标头。如果您声明 它作为一个豆子,名字forwardedHeaderTransformer,它将被检测和使用。spring-doc.cadn.net.cn

在 5.1 中ForwardedHeaderFilter已被弃用并被ForwardedHeaderTransformer因此,请求头转发可以更早地处理,在 交换被创建。如果仍然配置了过滤器,则它将从 过滤器,以及ForwardedHeaderTransformer而是使用。

安全注意事项

请求头转发存在安全注意事项,因为应用程序无法知道 如果标头是由代理按预期添加的,还是由恶意客户端添加的。这就是为什么 应配置信任边界处的代理,以删除传入的不受信任的转发流量 从外面看。您还可以配置ForwardedHeaderTransformerremoveOnly=true,在这种情况下,它会删除但不使用标头。spring-doc.cadn.net.cn

过滤器

WebHandler应用程序接口,您可以使用WebFilter应用拦截样式 过滤器和目标处理链其余部分之前和之后的逻辑WebHandler.使用 WebFlux Config 时,注册WebFilter就这么简单 将其声明为 Spring bean 并(可选)通过使用@Order上 bean 声明或通过实现Ordered.spring-doc.cadn.net.cn

CORS

Spring WebFlux 通过对 CORS 配置的注释提供细粒度的支持 控制器。但是,当您将其与 Spring Security 一起使用时,我们建议依赖内置的CorsFilter,必须在 Spring Security 的过滤器链之前订购。spring-doc.cadn.net.cn

请参阅有关 CORSCORSWebFilter了解更多详情。spring-doc.cadn.net.cn

URL 处理程序

您可能希望控制器端点匹配 URL 路径中带有或不带有尾随斜杠的路由。 例如,“GET /home”和“GET /home/”都应由带有@GetMapping("/home").spring-doc.cadn.net.cn

将尾随斜杠变体添加到所有映射声明并不是处理此用例的最佳方法。 这UrlHandlerFilterWeb 过滤器就是为此目的而设计的。它可以配置为:spring-doc.cadn.net.cn

  • 在收到带有尾随斜杠的 URL 时响应 HTTP 重定向状态,将浏览器发送到非尾随斜杠 URL 变体。spring-doc.cadn.net.cn

  • 更改请求,使其就像发送请求时没有尾随斜杠一样,并继续处理请求。spring-doc.cadn.net.cn

以下是如何实例化和配置UrlHandlerFilter对于博客应用程序:spring-doc.cadn.net.cn

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.spring-doc.cadn.net.cn

下表描述了可用的WebExceptionHandler实现:spring-doc.cadn.net.cn

异常处理程序 描述

ResponseStatusExceptionHandlerspring-doc.cadn.net.cn

提供对类型ResponseStatusException通过将响应设置为异常的 HTTP 状态代码。spring-doc.cadn.net.cn

WebFluxResponseStatusExceptionHandlerspring-doc.cadn.net.cn

扩展ResponseStatusExceptionHandler也可以确定 HTTP 状态代码@ResponseStatus任何异常的注释。spring-doc.cadn.net.cn

此处理程序在 WebFlux 配置中声明。spring-doc.cadn.net.cn

Codec

spring-webspring-core模块支持序列化和 通过非阻塞 I/O 将字节内容反序列化到更高级别对象或从更高级别对象反序列化 反应流背压。下面介绍了此支持:spring-doc.cadn.net.cn

spring-core模块提供byte[],ByteBuffer,DataBuffer,ResourceString编码器和解码器实现。这spring-web模块提供 Jackson JSON、Jackson Smile、JAXB2、协议缓冲区和其他编码器和解码器以及 表单数据、多部分内容、 服务器发送的事件等。spring-doc.cadn.net.cn

ClientCodecConfigurerServerCodecConfigurer通常用于配置和 自定义要在应用程序中使用的编解码器。请参阅有关配置 HTTP 消息编解码器的部分。spring-doc.cadn.net.cn

Jackson JSON

JSON 和二进制 JSON(微笑)是 当 Jackson 库存在时,两者都受支持。spring-doc.cadn.net.cn

Jackson2Decoder工作原理如下:spring-doc.cadn.net.cn

  • Jackson 的异步、非阻塞解析器用于聚合字节块流 到TokenBuffer的每个代表一个 JSON 对象。spring-doc.cadn.net.cn

  • TokenBuffer传给Jackson的ObjectMapper以创建更高级别的对象。spring-doc.cadn.net.cn

  • 解码到单值发布者时(例如Mono),有一个TokenBuffer.spring-doc.cadn.net.cn

  • 解码为多值发布者时(例如Flux),每个TokenBuffer被传递给 这ObjectMapper一旦收到完全格式对象的足够字节。这 输入内容可以是 JSON 数组,也可以是任何以行分隔的 JSON 格式,例如 NDJSON、 JSON 行或 JSON 文本序列。spring-doc.cadn.net.cn

Jackson2Encoder工作原理如下:spring-doc.cadn.net.cn

  • 对于单个值发布商(例如Mono),只需通过ObjectMapper.spring-doc.cadn.net.cn

  • 对于具有application/json,默认情况下使用Flux#collectToList(),然后序列化生成的集合。spring-doc.cadn.net.cn

  • 对于具有流媒体类型(如application/x-ndjsonapplication/stream+x-jackson-smile、编码、写入和 使用行分隔的 JSON 格式单独刷新每个值。其他 流媒体类型可以注册到编码器。spring-doc.cadn.net.cn

  • 对于 SSE,Jackson2Encoder每个事件调用,并刷新输出以确保 立即交货。spring-doc.cadn.net.cn

默认情况下,两者Jackson2EncoderJackson2Decoder不支持类型String.相反,默认假设是一个字符串或字符串序列 表示序列化的 JSON 内容,由CharSequenceEncoder.如果什么 您需要从Flux<String>Flux#collectToList()和 对Mono<List<String>>.spring-doc.cadn.net.cn

表单数据

FormHttpMessageReaderFormHttpMessageWriter支持解码和编码application/x-www-form-urlencoded内容。spring-doc.cadn.net.cn

在经常需要从多个地方访问表单内容的服务器端,ServerWebExchange提供专用的getFormData()解析内容的方法 通过FormHttpMessageReader然后缓存结果以供重复访问。 请参阅WebHandler应用程序接口部分。spring-doc.cadn.net.cn

一次getFormData()使用时,无法再从 请求正文。因此,申请应通过ServerWebExchange一致地访问缓存的表单数据,而不是从原始请求正文中读取。spring-doc.cadn.net.cn

多部分

MultipartHttpMessageReaderMultipartHttpMessageWriter支持解码和 对“multipart/form-data”、“multipart/mixed”和“multipart/related”内容进行编码。 挨次MultipartHttpMessageReader委托给另一个HttpMessageReader用于实际解析为Flux<Part>然后简单地将这些部件收集到MultiValueMap. 默认情况下,DefaultPartHttpMessageReader,但这可以通过ServerCodecConfigurer. 有关DefaultPartHttpMessageReader,请参阅javadoc 的DefaultPartHttpMessageReader.spring-doc.cadn.net.cn

在服务器端,可能需要从多个 地方ServerWebExchange提供专用的getMultipartData()解析的方法 内容通过MultipartHttpMessageReader然后缓存结果以供重复访问。 请参阅WebHandler应用程序接口部分。spring-doc.cadn.net.cn

一次getMultipartData()使用时,无法再从 请求正文。因此,应用程序必须始终使用getMultipartData()用于重复、类似地图的部件访问,或以其他方式依赖SynchronossPartHttpMessageReader一次性访问Flux<Part>.spring-doc.cadn.net.cn

协议缓冲区

ProtobufEncoderProtobufDecoder支持解码和编码“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 及更高版本。spring-doc.cadn.net.cn

ProtobufJsonDecoderProtobufJsonEncoder变体支持在 Protobuf 消息中读取和写入 JSON 文档。 它们需要“com.google.protobuf:protobuf-java-util”依赖项。请注意,JSON 变体不支持读取消息流, 请参阅javadoc 的ProtobufJsonDecoder了解更多详情。spring-doc.cadn.net.cn

限制

DecoderHttpMessageReader缓冲部分或全部输入的实现stream 可以配置为内存中缓冲的最大字节数限制。在某些情况下,缓冲是因为输入被聚合并表示为单个对象 — 例如,具有@RequestBody byte[],x-www-form-urlencoded数据,依此类推。缓冲也可能发生在流式处理中,当拆分输入流——例如,分隔文本、JSON 对象流和等等。对于这些流式处理情况,限制适用于关联的字节数与流中的一个对象。spring-doc.cadn.net.cn

要配置缓冲区大小,您可以检查给定的DecoderHttpMessageReader公开一个maxInMemorySize属性,如果是这样,Javadoc 将包含有关默认值的详细信息 值。 在服务器端,ServerCodecConfigurer提供了一个单一的地方设置所有编解码器,请参阅 HTTP 消息编解码器。在客户端,限制所有编解码器都可以在 WebClient.Builder 中更改。spring-doc.cadn.net.cn

对于多部分解析maxInMemorySize属性限制非文件部件的大小。对于文件部件,它决定了部件的阈值被写入磁盘。对于写入磁盘的文件部件,还有一个额外的maxDiskUsagePerPart属性来限制每个部分的磁盘空间量。还有 一个maxParts属性来限制多部分请求中的部分总数。要在 WebFlux 中配置所有三个部分,您需要提供预配置的实例MultipartHttpMessageReaderServerCodecConfigurer.spring-doc.cadn.net.cn

流式传输到 HTTP 响应时(例如text/event-stream,application/x-ndjson),定期发送数据非常重要,以便尽早可靠地检测断开连接的客户端。这样的发送可以是一个仅注释、空 SSE 事件或任何其他“无作”数据,这些数据将有效地充当心跳。spring-doc.cadn.net.cn

DataBuffer

DataBuffer是 WebFlux 中字节缓冲区的表示形式。的 Spring Core 部分 此参考在数据缓冲区和编解码器部分中有更多相关内容。要理解的关键点是,在某些 像 Netty 这样的服务器,字节缓冲区被池化并对引用进行计数,并且必须释放 使用时以避免内存泄漏。spring-doc.cadn.net.cn

WebFlux 应用程序通常不需要关注此类问题,除非它们 直接使用或生成数据缓冲区,而不是依赖编解码器进行转换 以及来自更高级别的对象,或者除非他们选择创建自定义编解码器。对于这样的 情况请查看数据缓冲区和编解码器中的信息, 尤其是关于使用 DataBuffer 的部分。spring-doc.cadn.net.cn

Logging

DEBUGSpring WebFlux 中的级别日志记录被设计为紧凑、最小和 人性化。它侧重于对 与其他仅在调试特定问题时有用的其他问题相比。spring-doc.cadn.net.cn

TRACE关卡日志记录通常遵循与DEBUG(例如,还 不应是消防水带),但可用于调试任何问题。此外,一些日志 消息可能会在TRACEDEBUG.spring-doc.cadn.net.cn

良好的日志记录来自使用日志的经验。如果你发现任何可以 未达到既定目标,请告诉我们。spring-doc.cadn.net.cn

日志 ID

在 WebFlux 中,单个请求可以在多个线程上运行,并且线程 ID 对于关联属于特定请求的日志消息没有用处。这就是为什么 默认情况下,WebFlux 日志消息以特定于请求的 ID 为前缀。spring-doc.cadn.net.cn

在服务器端,日志 ID 存储在ServerWebExchange属性 (LOG_ID_ATTRIBUTE), 而基于该 ID 的完整格式化前缀可从ServerWebExchange#getLogPrefix().在WebClientside,日志 ID 存储在ClientRequest属性 (LOG_ID_ATTRIBUTE) ,而完全格式化的前缀可从ClientRequest#logPrefix().spring-doc.cadn.net.cn

敏感数据

DEBUGTRACE日志记录可以记录敏感信息。这就是为什么 form 参数和 默认情况下,标头是屏蔽的,您必须显式启用其完全日志记录。spring-doc.cadn.net.cn

以下示例显示了如何对服务器端请求执行此作:spring-doc.cadn.net.cn

@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)
	}
}

以下示例演示如何对客户端请求执行此作:spring-doc.cadn.net.cn

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()

附加者

SLF4J 和 Log4J 2 等日志记录库提供异步记录器,避免 阻塞。虽然这些都有其自身的缺点,例如可能会丢弃消息 无法排队记录,它们是目前最好的可用选项 用于响应式、非阻塞应用程序。spring-doc.cadn.net.cn

自定义编解码器

应用程序可以注册自定义编解码器以支持其他媒体类型, 或默认编解码器不支持的特定行为。spring-doc.cadn.net.cn

开发人员表达的某些配置选项在默认编解码器上强制执行。 自定义编解码器可能希望有机会与这些偏好保持一致, 例如强制执行缓冲限制记录敏感数据spring-doc.cadn.net.cn

以下示例演示如何对客户端请求执行此作:spring-doc.cadn.net.cn

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()