[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`相關實現類結構如下:

| 類 | 作用 |
| --- | --- |
|`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()),默認不使用|

## 簡單的服務器
上面介紹了`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....
```
- 1.反應式編程概述
- 2.Reactor框架
- Flux
- Mono
- 訂閱(Subscribe)
- 編程創建序列
- 線程和調度器
- 錯誤處理
- 3.Spring WebFlux概述
- 4.Spring WebFlux核心組件
- HttpHandler
- WebHandler
- ServerWebExchange
- 編碼和解碼器
- JSON
- Form Data
- Multipart Data
- 過濾器
- 異常處理器
- DispatcherHandler
- 5.Spring Boot啟動WebFlux
- 6.Spring WebFlux注解控制器
- 請求映射
- 處理程序方法
- 方法參數
- 返回值
- 類型轉換
- 模型(Model)
- 數據綁定(DataBinder)
- 異常管理
- @ControllerAdvice
- 7.Spring WebFlux函數端點
- HandlerFunction
- RouterFunction
- 運行服務
- 函數過濾器
- 8.Spring Boot中使用函數端點
- 9.Spring Webflux請求處理流程
- 10.Spring WebFlux配置
- 11.Spring WebFlux使用R2DBC訪問MySQL
- 12.Spring WebFlux訪問Redis
- 13.Spring WebFlux訪問MongoDB
- 14.Spring WebFlux集成Thymeleaf
- 15.Spring WebFlux集成FreeMarker
- 16.Spring WebFlux WebClient
- 17.Spring WebFlux WebSocket
- 18.測試
- 19.RSocket