[TOC] ## `WebHandler`简介 `WebHandler`用于请求处理的通用`Web API`,在此基础上构建具体的编程模型,如带注释的控制器和函数端点。 `org.springframework.web.server`包构建在`HttpHandler`契约之上,提供一个通用的`Web API`,通过由多个`WebExceptionHandler`、多个`WebFilter`、和一个`WebHandler`组件组成链来处理请求。该链可以与`WebHttpHandlerBuilder`放在一起,只需指定一个自动检测组件的`Spring ApplicationContext`。或通过向构建器注册组件。 `HttpHandler`的目标很简单,就是抽象不同`HTTP`服务器的使用,而`WebHandler API`的目标是提供`Web`应用程序中常用的特性,比如: 1. 带有属性的用户会话。 2. 解决请求的`Locale`或`Principal` 3. 访问解析和缓存的表单数据 4. 对复合数据的抽象 `WebHandler`相关实现类结构如下: ![](https://img.kancloud.cn/1d/af/1dafc1d5567181b4eb42fdc143b2277a_1600x626.png) | 类 | 作用 | | --- | --- | |`DispatcherHandler`|`HTTP`请求处理程序/控制器的中央调度程序。调度到已注册的处理程序以处理请求,类似`Spring Mvc`中的`DispatchServlet`| |`FilteringWebHandler`|在调用委托的`WebHandler`之前调用一个`WebFilter`链,进行过滤处理,类似`Servlet`中的`Filter` |`ExceptionHandlingWebHandler`|用于异常处理 |`ResourceWebHandler`|用于静态资源处理| | `HttpWebHandlerAdapter` | `WebHandler`到`HttpHandle`转换的默认适配器 | ## `WebHttpHandlerBuilder` 这个构建器有两个目的: 1. 一种是组装一个处理链,它包含一个目标`WebHandler`,然后用一组`WebFilters`进行修饰,然后进一步用一组`WebExceptionHandler`进行修饰。 2. 第二个目的是将产生的处理链调整为`HttpHandler`:最低级别的反应式`HTTP`处理抽象,然后可以将其用于任何受支持的运行时。适配是在`HttpWebHandlerAdapter`的帮助下完成的。 处理链可以通过构建器方法手工组装,或者通过`ApplicationContext`从`Spring ApplicationContext`中检测,或者两者都可以。 ~~~ WebHttpHandlerBuilder.applicationContext(...).filter(...).webHandler(...).exceptionHandler(...) .sessionManager(...).codecConfigurer(...).localeContextResolver(...).forwardedHeaderTransformer(...); ~~~ 下表列出了`WebHttpHandlerBuilder`可以在`Spring ApplicationContext`中自动检测或直接注册的组件: | Bean name | Bean type | Count| Description| | --- | --- |--- |--- | | 任意 | WebExceptionHandler |0..N| 为来自WebFilter实例链和目标WebHandler的异常提供处理 | |任意| WebFilter| 0..N| 在调用目标的`WebHandler`之前调用一个`WebFilter`链,进行过滤处理| |webHandler|WebHandler|1|请求的处理程序| |webSessionManager|WebSessionManager|0..1|管理WebSession实例通过ServerWebExchange公开的方法,默认DefaultWebSessionManager| |serverCodecConfigurer|ServerCodecConfigurer|0..1|用于访问HttpMessageReader实例,解析表单数据和ServerWebExchange通过方法获取的复合数据,默认ServerCodecConfigurer.create()| |localeContextResolver|LocaleContextResolver|0..1|LocaleContext解析器,通过ServerWebExchange上公开的方法| |forwardedHeaderTransformer|ForwardedHeaderTransformer|0..1|从“Forwarded”和“X-Forwarded-*”头中提取值来覆盖请求URI(即ServerHttpRequest.getURI()),默认不使用| ![](https://img.kancloud.cn/ed/af/edafe3bc127e05c924fe4a5a101901a4_946x624.png) ## 简单的服务器 上面介绍了`WebHandler`相关组件,以及链路的处理顺序,接下来使用`reactor-netty`创建一个简单的服务器,处理网络请求,更直观的了解`WebHandler`相关想组件的执行流程。 1.引入依赖 ~~~ <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webflux</artifactId> <version>5.3.16</version> <exclusions> <exclusion> <groupId>io.projectreactor</groupId> <artifactId>reactor-core</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.3.16</version> </dependency> <dependency> <groupId>io.projectreactor.netty</groupId> <artifactId>reactor-netty</artifactId> <version>1.0.19</version> </dependency> <dependency> <groupId>io.projectreactor</groupId> <artifactId>reactor-core</artifactId> <version>3.4.18</version> </dependency> ~~~ 2.`DataBuffer` 公共创建方法 ~~~ static DataBuffer createDataBuffer() { DataBufferFactory dataBufferFactory = new DefaultDataBufferFactory(); DataBuffer dataBuffer = dataBufferFactory.allocateBuffer(); return dataBuffer; } ~~~ 3.创建`ServerCodecConfigurer` ~~~ static ServerCodecConfigurer codecConfigurer() { System.out.println("进入codecConfigurer..."); return ServerCodecConfigurer.create(); } ~~~ 4.创建`AcceptHeaderLocaleContextResolver` ~~~ static AcceptHeaderLocaleContextResolver localeContextResolver() { System.out.println("进入localeContextResolver..."); return new AcceptHeaderLocaleContextResolver(); } ~~~ 5.创建`ForwardedHeaderTransformer` ~~~ static ForwardedHeaderTransformer forwardedHeaderTransformer() { System.out.println("进入forwardedHeaderTransformer..."); return new ForwardedHeaderTransformer(); } ~~~ 6.创建`WebSessionManager` ~~~ static WebSessionManager webSessionManager() { return exchange -> { System.out.println("进入WebSessionManager..."); Mono<WebSession> memory = new InMemoryWebSessionStore().retrieveSession("user_id"); return memory; }; } ~~~ 7.创建`WebFilter` ~~~ static WebFilter webFilter() { return (exchange, chain) -> { System.out.println("进入filter..."); return chain.filter(exchange); }; } ~~~ 8.创建`WebHandler` ~~~ static WebHandler webHandler() { return exchange -> { System.out.println("进入WebHandler...."); DataBuffer dataBuffer = createDataBuffer().write("hello word".getBytes()); return exchange.getResponse().writeWith(Flux.just(dataBuffer)); }; } ~~~ 9.创建`WebExceptionHandler` ~~~ static WebExceptionHandler webExceptionHandler() { return (exchange, ex) -> { System.out.println("进入exceptionHandler..."); return exchange.getResponse().writeWith(Flux.just(createDataBuffer().write(ex.getMessage().getBytes()))); }; } ~~~ 10.创建服务`HttpServer` ~~~ public static void main(String[] args) throws Exception { HttpHandler handler = WebHttpHandlerBuilder.webHandler(webHandler()).filter(webFilter()). exceptionHandler(webExceptionHandler()).sessionManager(webSessionManager()) .codecConfigurer(codecConfigurer()).localeContextResolver(localeContextResolver()) .forwardedHeaderTransformer(forwardedHeaderTransformer()).build(); ReactorHttpHandlerAdapter adapter = new ReactorHttpHandlerAdapter(handler); HttpServer.create().host("127.0.0.1").port(1234).handle(adapter).bind().block(); Thread.currentThread().join(); } } ~~~ 11.执行结果 ``` ➜ ~ curl -i 'http://127.0.0.1:1234' HTTP/1.1 200 OK transfer-encoding: chunked hello word ``` 12.日志 ``` 进入codecConfigurer... 进入localeContextResolver... 进入forwardedHeaderTransformer... 进入WebSessionManager... 进入filter... 进入WebHandler.... ```