如何在Spring WebFlux的任何地方获取Request对象

网友投稿 2433 2023-02-16

如何在Spring WebFlux的任何地方获取Request对象

如何在Spring WebFlux的任何地方获取Request对象

1 不一样的世界

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

ServletRequestAttributes requestAttributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();

// get the request

HttpServletRequest 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 filter(ServerWebExchange exchange, WebFilterChain chain);

我们可以通过ServerWebExchange直接获取到Request对象:

ServerHttpRequest request = exchange.getRequest();

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

针对问题(2),需要一个与Reavtive请求相同范围的容器,reactor.util.context.Context可以满足需求。查看reactor的官方文档(https://projectreactor.io/docs/core/release/reference/#context )可见下面这段话:

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 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

实现一个工具类来提供静态方法,http://在Filter后的任何场景都可以使用:

public class ReactiveRequestContextHolder {

public static final Class CONTEXT_KEY = ServerHttpRequest.class;

public static Mono getRequest() {

return Mono.subscriberContext()

.map(ctx -> ctx.get(CONTEXT_KEY));

}

}

3.3 在Controller中使用

我们尝试在Controller中使用ReactiveRequestContextHolder来获取Request:

@RestController

public class GetRequestController {

@RequestMapping("/request")

public Mono 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/requeGHKGOst -H 'user: pkslow.com'

pkslow.com

可以成功获取请求头user。

4 总结

代码请查看:https://github.com/LarryDpk/pkslow-samples

以上就是如何在Spring WebFlux的任何地方获取Request对象的详细内容,更多关于Spring WebFlux获取Request对象的资料请关注我们其它相关文章!

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:Spring Boot事务配置详解
下一篇:在微信小程序里调用api(小程序接入api)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~