环境:Springboot2.4.12
概述
spring-web模块包含了对响应式web应用程序的以下基本支持:
- 对于服务器请求处理,有两个级别的支持。
- HttpHandler:处理HTTP请求的基本协议,包括非阻塞I/O和响应式流背压,以及Reactor Netty、Undertow、Tomcat、Jetty和任何Servlet 3.1+容器的适配器。
- WebHandler API:稍微高级一点的,用于处理请求的通用web API,在此基础上构建具体的编程模型,如带注释的控制器和函数式端点。
- 对于客户端,有一个基本的ClientHttpConnector契约来执行HTTP请求,包括非阻塞I/O和响应式流回压,以及Reactor Netty, Reactive Jetty HttpClient和Apache HttpComponents的适配器。应用程序中使用的高级web客户端构建在这个基本契约之上。
- 对于客户端和服务器,用于HTTP请求和响应内容的序列化和反序列化的编解码器。
HttpHandler
HttpHandler是一个简单的协议,只有一个方法来处理请求和响应。它故意最小化,其主要和唯一的目的是在不同的HTTP服务器api上提供最小的抽象。
支持的服务器api如下表所示:
服务器 | 服务的API | 反应式流支持 |
Netty | Netty API | Reactor Netty |
Undertow | Undertow API | spring-web: Undertow到Reactive Streams桥接 |
Tomcat | Servlet 3.1 non-blocking I/O; Tomcat API to read and write ByteBuffers vs byte[] | spring-web:Servlet 3.1非阻塞 I/O到Reactive Streams桥接 |
Jetty | Servlet 3.1 non-blocking I/O; Jetty API to write ByteBuffers vs byte[] | spring-web:Servlet 3.1非阻塞 I/O到Reactive Streams桥接 |
Servlet 3.1 container | Servlet 3.1 non-blocking I/O | spring-web: Servlet 3.1非阻塞 I/O到Reactive Streams桥接 |
下表描述了服务器依赖关系:
服务器 | Group id | Artifact name |
Reactor Netty | io.projectreactor.netty | reactor-netty |
Undertow | io.undertow | undertow-core |
Tomcat | org.apache.tomcat.embed | tomcat-embed-core |
Jetty | org.eclipse.jetty | jetty-server, jetty-servlet |
下面的代码片段显示了在每个服务器API中使用HttpHandler适配器:
- Reactor Netty
- Undertow
- Tomcat
- Jetty
- Servlet 3.1+ Container
要将war部署到任何Servlet 3.1+容器,你可以扩展并在war中包含
AbstractReactiveWebInitializer。这个类用ServletHttpHandlerAdapter封装了一个HttpHandler,并将其注册为Servlet。
部分源码:
WebHandler
org.springframework.web.server包构建在HttpHandler契约之上,为通过多个WebExceptionHandler、多个WebFilter和单个WebHandler组件的链处理请求提供通用的web API。只需指向自动检测组件的Spring ApplicationContext,或者向构建器注册组件,就可以将该链与WebHttpHandlerBuilder组合在一起。
HttpHandler的目标很简单,就是抽象出不同的HTTP服务器,而WebHandler API的目标是提供web应用中常用的更广泛的功能,例如:
- 具有属性的用户会话
- 请求属性
- 已解析请求的区域设置或主体
- 访问已解析和缓存的表单数据
- 多部分数据的摘要。
- 等等
特殊bean类型
下表列出了WebHttpHandlerBuilder可以在Spring ApplicationContext中自动检测或直接注册的组件:
Bean name | Bean type | Count | Description |
<any> | WebExceptionHandler | 0..N | 为来自WebFilter实例链和目标WebHandler的异常提供处理。 |
<any> | WebFilter | 0..N | 在过滤器链的其余部分和目标WebHandler的前后应用拦截样式逻辑。 |
webHandler | WebHandler | 1 | 请求处理程序。 |
webSessionManager | WebSessionManager | 0..1 | 通过ServerWebExchange上的方法公开的WebSession实例管理器。默认为DefaultWebSessionManager。 |
serverCodecConfigurer | ServerCodecConfigurer | 0..1 | 用于访问HttpMessageReader实例,解析表单数据和multipart数据,然后通过ServerWebExchange上的方法公开这些数据。默认情况下是servercodecconfiguration.create()。 |
localeContextResolver | LocaleContextResolver | 0..1 | LocaleContext的解析器通过ServerWebExchange上的方法公开。默认为AcceptHeaderLocaleContextResolver。 |
forwardedHeaderTransformer | ForwardedHeaderTransformer | 0..1 | 对于处理转发的类型头,可以提取并删除它们,也可以只删除它们。默认不使用。 |
Form Data
ServerWebExchange公开了以下访问表单数据的方法:
DefaultServerWebExchange使用配置的HttpMessageReader将表单数据(
application/x-www-form-urlencoded)解析为MultiValueMap。默认情况下,FormHttpMessageReader被配置为由ServerCodecConfigurer bean使用。
Multipart Data
ServerWebExchange公开了以下访问多部分数据的方法:
DefaultServerWebExchange使用配置的HttpMessageReader<MultiValueMap<String, Part>>来将multipart/form-data内容解析为MultiValueMap。默认情况下,这是DefaultPartHttpMessageReader,它没有任何第三方依赖。另外,还可以使用基于Synchronoss nio Multipart库的SynchronossPartHttpMessageReader。两者都是通过ServerCodecConfigurer bean进行配置的。
要以流式方式解析多部分数据,你可以使用HttpMessageReader<Part>返回的` Flux<Part> `。例如,在带注释的控制器中,使用@RequestPart意味着通过名称访问各个部分,就像map一样,因此需要完整解析多个部分的数据。相比之下,可以使用@RequestBody将内容解码到Flux<Part>,而无需收集到MultiValueMap。
Filters
在WebHandler API中,你可以使用WebFilter在过滤器和目标WebHandler处理链的其余部分之前和之后应用拦截风格的逻辑。当使用WebFlux配置时,注册WebFilter就像把它声明为Spring bean一样简单,并且(可选地)通过在bean声明上使用@Order或实现Ordered来表示优先级。
Exceptions
在WebHandler API中,可以使用WebExceptionHandler来处理来自WebFilter实例链和目标WebHandler的异常。当使用WebFlux配置时,注册WebExceptionHandler就像声明它为Spring bean一样简单,并且(可选)通过在bean声明上使用@Order或实现Ordered来表示优先级。
下表描述了可用的WebExceptionHandler实现:
Exception Handler | Description |
ResponseStatusExceptionHandler | 通过将响应设置为异常的HTTP状态码,提供对ResponseStatusException类型异常的处理。 |
WebFluxResponseStatusExceptionHandler | 扩展了ResponseStatusExceptionHandler,它还可以确定任何异常的@ResponseStatus注解的HTTP状态码。 这个处理程序是在WebFlux配置中声明的。 |
Codecs
spring-web和spring-core模块通过非阻塞I/O提供响应式流回压,支持序列化和反序列化与高层对象之间的字节内容。下面介绍这种支持:
- Encoder与Decoder是底层协议,独立于HTTP对内容进行编码和解码。
- HttpMessageReader和HttpMessageWriter是编码和解码HTTP消息内容的协议。
- Encoder可以使用EncoderHttpMessageWriter包装,以适应在web应用程序中使用,而 Decoder可以使用DecoderHttpMessageReader包装。
- DataBuffer抽象了不同的字节缓冲区表示形式(例如Netty ByteBuf、java.nio。ByteBuffer等),也是所有编解码器都能处理的。
spring-core模块提供了byte[]、ByteBuffer、DataBuffer、Resource和String编码器和解码器的实现。spring-web模块提供了Jackson JSON、Jackson Smile、JAXB2、Protocol buffer和其他Encoder和Decoder,以及针对表单数据、多部分内容、服务器发送事件等只支持web的HTTP消息阅读器和writer实现。