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

 更新时间:2021年01月26日 10:53:06   作者:南瓜慢说  
这篇文章主要介绍了如何在Spring WebFlux的任何地方获取Request对象,帮助大家更好的理解和使用springboot框架,感兴趣的朋友可以了解下

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

@RestController
public 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/pkslow-samples

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

相关文章

  • vue3实现一个todo-list

    vue3实现一个todo-list

    这篇文章主要为大家详细介绍了基于vuejs实现一个todolist项目,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能给你带来帮助
    2021-08-08
  • Java运算符解密之位运算、移位运算举例详解

    Java运算符解密之位运算、移位运算举例详解

    这篇文章主要介绍了Java运算符解密之位运算、移位运算的相关资料,Java中的位运算符包括按位与&、按位或|、按位取反~和按位异或^,用于对数据的二进制位进行操作,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2025-04-04
  • IDEA类和方法注释模板设置(非常详细)

    IDEA类和方法注释模板设置(非常详细)

    这篇文章主要介绍了IDEA类和方法注释模板设置(非常详细),小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-08-08
  • Java使用POI-TL和JFreeChart动态生成Word报告

    Java使用POI-TL和JFreeChart动态生成Word报告

    本文介绍了使用POI-TL和JFreeChart生成包含动态数据和图表的Word报告的方法,并分享了实际开发中的踩坑经验,通过代码示例讲解的非常详细,具有一定的参考价值,需要的朋友可以参考下
    2025-02-02
  • 如何使用IDEA新建一个普通的Javaweb项目

    如何使用IDEA新建一个普通的Javaweb项目

    今天给大家普及如何使用IDEA新建一个普通的Javaweb项目及配置tomcat的方法,在文末给大家提到如果不想每次都重启tomcat,可以设置快捷方式,对idea新建Javaweb项目感兴趣的朋友一起看看吧
    2021-06-06
  • JAVA判断两个时间之间的差

    JAVA判断两个时间之间的差

    经常会遇到需要判断两个时间之间的差异的情况,本文主要介绍了JAVA计算两个时间之间的差,具有一定的参考价值,感兴趣的可以了解一下
    2023-12-12
  • springboot项目获取resources相对路径的方法

    springboot项目获取resources相对路径的方法

    这篇文章主要介绍了springboot项目获取resources相对路径的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-12-12
  • 往DAO类中注入@PersistenceContext和@Resource的区别详解

    往DAO类中注入@PersistenceContext和@Resource的区别详解

    这篇文章主要介绍了往DAO类中注入@PersistenceContext和@Resource的区别详解,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-02-02
  • 关于SpringBoot改动后0.03秒启动的问题

    关于SpringBoot改动后0.03秒启动的问题

    这篇文章主要介绍了SpringBoot改动后0.03秒启动,本文结合示例代码给大家讲解的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-12-12
  • 关于feign.codec.DecodeException异常的解决方案

    关于feign.codec.DecodeException异常的解决方案

    这篇文章主要介绍了关于feign.codec.DecodeException异常的解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-03-03

最新评论