当通过
subscribe获取body体的时候,总是报null。Spring Boot版本:2.1.1.RELEASE
官方样例
Spring官方有一个样例:spring-boot-sample-webflux
包含一个启动类、2个Controller和一个Handler。

Controller是两个基本的基于@RestController注解的Controller类,与以往@Controller注解的区别就是包含了@RequestBody注解。这次主要就是看看这个Handler类
1 |
|
1 |
|
通过Bean注册路由信息,这和以往的@Controller有所不同,但是和Vert.x很相似。在Handler中通过ServerRequest接口接收请求信息。
1 | // Vert.x 路由部署方式 |
运行样例:
使用Httpie携带Body 信息请求/echo,返回请求的Body信息
1 | E:\spring-boot-sample-webflux>http post :8080/echo foo=bar |
获取请求
上面的实例可以获取Body信息,但是当我们想subscribe获取这个body内的信息时,会得到一个null的对象。
错误代码:
1 | request.bodyToMono(String.class) |
在Spring Boot#15320找到了答案
1 | This code is calling subscribe on the request body and decouples it from the response rendering. |
主要意思就是:
1 | 调用subscribe()方法获取请求体会割裂响应,此时正处于竞争态。 |
所以想对Body做操作时,需要链式调用,最好不要使用订阅等方法,而且这里还处于竞争态,更不能使用。所以单独获取Body或者某一请求值的话,直接使用flatMap()方法
1 | public Mono<ServerResponse> test2(ServerRequest request) { |
这样就可以在flatMap()操作body了,同时在后面加上了log()。看下调用情况
1 | 2019-01-11 15:19:25.971 INFO 19612 --- [ctor-http-nio-2] reactor.Mono.FlatMap.2 : | onSubscribe([Fuseable] MonoFlatMap.FlatMapMain) |
可以在第五行看到onNext({"foo": "bar"}),显示出了请求体。同时可以看到,reactor.Mono.OnErrorResume.1这里是调用了OnErrorResume方法,我理解就是存在竞争,它是从错误中恢复出来的。
当获取多个参数时,需要使用zip()方法将几个参数zip在一起,例如获取请求IP和请求体
1 | public Mono<ServerResponse> test(ServerRequest request) { |
请求/test端点
1 | C:\spring-boot-sample-webflux>http post :8080/test foo=bar |
总结
想要在Spring 5,Spring Boot 2上得到更好的体验。可以尝试转到流式编程上,包括使用lambda表达式等。可以增加代码的可读性和整洁性。
在这个例子里面,主要是获取多个请求参数,我自己也绕了好久,从以往的注解中跳出来。更多的可以看看Pivotal开源的Reactor或者RxJava等等。
结束!🔚
