怎么在webflux切面中获取请求头.

发布于 2022-09-12 00:10:46 字数 2965 浏览 26 评论 0

问题描述.

萌新在线踩坑....

我需要在切面中获取当前用户的请求信息,比如请求头信息.
但是不能像mvc一样通过以下方式实现.

@Autowired
private HttpServletRequest request;
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();

// 获取 request
HttpServletRequest request = requestAttributes.getRequest();

问题出现的环境背景及自己尝试过哪些方法

我尝试过自己创建一个ReactiveRequestContextHolder来获取
https://segmentfault.com/a/1190000018766412
但是返回是null.

之后

根据官方文档
https://projectreactor.io/docs/core/release/reference/#context
和reactor相关的文章
https://www.jianshu.com/p/1be25b134ced
发现reactor的context有 自底向上 的特性.所以我懵逼了.不知道该怎么实现了.

相关代码

我参考了以上的文章的代码.
以下是我的代码(我可能哪里理解错误了).

// 拦截器
// 把request对象放入Mono上下文中,key为一个class对象

@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));
    }
}
// 上下文
// 从Mono中获取上下文,key为一个class对象

public class ReactiveRequestContextHolder {
    public static final Class<ServerHttpRequest> CONTEXT_KEY = ServerHttpRequest.class;

    public static Mono<ServerHttpRequest> getRequest() {
        return Mono.subscriberContext()
                // TODO 报错了 reactor.core.Exceptions$ErrorCallbackNotImplemented: java.util.NoSuchElementException: Context is empty
                .map(ctx -> ctx.get(CONTEXT_KEY));
    }

}
// TODO 未完成 切面bean
// 过滤含有@test注解的控制层方法,取出名为testHeader的请求头信息并打印.

@Slf4j
@Aspect
@Component
@AllArgsConstructor
public class SecurityInnerAspect {

    // test 的内容被调用后进入切面
    @Around("@annotation(test)")
    // 不用JoinPoint 用 ProceedingJoinPoint,因为ProceedingJoinPoint可以拦截请求
    public Object around(ProceedingJoinPoint point, Inner inner) throws Throwable {
        ReactiveRequestContextHolder.getRequest().subscribe(serverHttpRequest -> {
            String header = Objects.requireNonNull(serverHttpRequest.getHeaders().get("testHeaderStr")).get(0);
            log.info("print testHeader: {}", header);
        });
        return point.proceed();
    }
}

期待的结果

我期待能在切面中取出用户request对象进行操作.
或能有其他解决方案.
感谢!!

实际看到的错误信息

本以为会通过spring的依赖反转拿到request对象,但是他没有和mvc一样的把当前用户的request对象注册成bean.也没有放到当前线程中.

且其他方式不太会用.

so,目前没有办法在切面bean中取出request信息

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

絕版丫頭 2022-09-19 00:10:46

解决方案

控制层添加ServerWebExchange参数,由框架自动注入.
ServerWebExchange封装了request和response.

@GetMapping("test")  
public Mono test(ServerWebExchange exchange) {  
    // 取到了
    final ServerHttpRequest request = exchange.getRequest();  
 return Mono.empty();  
}

在控制层是能取到该request参数的.

然后切面通过JoinPoint获取该方法的参数.

public Object around(ProceedingJoinPoint point, Inner inner) throws Throwable {  
    SecurityContextServerWebExchange securityContextServerWebExchange = null;  
 for (Object arg : point.getArgs()) {  
        if (arg instanceof SecurityContextServerWebExchange) {  
            securityContextServerWebExchange = (SecurityContextServerWebExchange) arg;  
  }  
    }  
    // 取到了
    final ServerHttpRequest request = securityContextServerWebExchange.getRequest();  
  
 return point.proceed();  
}

就可以取到request了.如果有更好更优雅更没有侵入性的方式的欢迎留言哦.

咋地 2022-09-19 00:10:46

题主解决了吗目前

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文