我最新最全的文章都在 南瓜慢说 www.pkslow.com ,欢送大家来喝茶!

1 不一样的世界

在惯例的Spring Web我的项目中,咱们要获取Request对象是十分不便的,不少库都提供了静态方法来获取。获取代码如下:

ServletRequestAttributes requestAttributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();// get the requestHttpServletRequest request = requestAttributes.getRequest();

在类RequestContextHolder提供了静态方法,也就意味着你能够在任何中央调用。而它应用了ThreadLocal来保留Request对象,也就是不同线程是能够获取各自的Request对象。

但在响应式WebFlux的世界里,并没有提供相似的Holder类,而WebFlux是无奈感知线程的,任何一个线程能够在任何时候解决任何申请,如果它感觉切换以后线程更有效率,它就会这么做。但在Servlet Based的利用里,它会为某个申请安顿一个线程去解决残缺个过程。

这个微小的差异,意味着不能简略地通过ThreadLocal来保留和获取Request了。

2 先保留,再获取

为了在前面能够不便取得Request对象,咱们就须要在开始的时候把它存在一个能够应用、并且是雷同scope的容器里。这里须要解决两个关键问题:

(1)Request对象从何而来;

(2)存在哪里?

针对问题(1), 咱们能够回忆什么时候会呈现Request对象,最容易想得到的就是WebFilter了,它的办法签名如下:

public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain);

咱们能够通过ServerWebExchange间接获取到Request对象:

ServerHttpRequest request = exchange.getRequest();

而因为Filter是能够先于应用逻辑执行的,所以满足要求,问题(1)解决。

针对问题(2),须要一个与Reavtive申请雷同范畴的容器,reactor.util.context.Context能够满足需要。查看reactor的官网文档(https://projectreactor.io/doc... )可见上面这段话:

Since version 3.1.0, Reactor comes with an advanced feature that is somewhat comparable to ThreadLocal but can be applied to a Flux or a Mono instead of a Thread. This feature is called Context.

并且官网也给出了为何ThreadLocal在某些场景不实用的解释,有趣味能够看看。

3 代码实现

3.1 WebFilter获取并保留

首先,在WebFilter中获取Request对象并保留,代码如下:

@Configuration@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)public class ReactiveRequestContextFilter implements WebFilter {    @Override    public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {        ServerHttpRequest request = exchange.getRequest();        return chain.filter(exchange)                .subscriberContext(ctx -> ctx.put(ReactiveRequestContextHolder.CONTEXT_KEY, request));    }}

ServerWebExchange中获取到ServerHttpRequest对象,再通过put办法把它放进Context里。

3.2 工具类Holder

实现一个工具类来提供静态方法,在Filter后的任何场景都能够应用:

public class ReactiveRequestContextHolder {    public static final Class<ServerHttpRequest> CONTEXT_KEY = ServerHttpRequest.class;    public static Mono<ServerHttpRequest> getRequest() {        return Mono.subscriberContext()                .map(ctx -> ctx.get(CONTEXT_KEY));    }}

3.3 在Controller中应用

咱们尝试在Controller中应用ReactiveRequestContextHolder来获取Request

@RestControllerpublic class GetRequestController {    @RequestMapping("/request")    public Mono<String> getRequest() {        return ReactiveRequestContextHolder.getRequest()                .map(request -> request.getHeaders().getFirst("user"));    }}

下面办法获取了Request对象,而后再获取了Request中的Header

启动利用,测试如下:

$ curl http://localhost:8088/request -H 'user: pkslow'pkslow$ curl http://localhost:8088/request -H 'user: larry'larry$ curl http://localhost:8088/request -H 'user: www.pkslow.com'www.pkslow.com

能够胜利获取申请头user

4 总结

代码请查看:https://github.com/LarryDpk/p...


欢送关注微信公众号<南瓜慢说>,将继续为你更新...

多读书,多分享;多写作,多整顿。