You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在Spring MVC项目中引入WebFlux路由,如何实现请求上下文传递?

解决方案:Spring MVC中为Reactive流注入请求上下文

在Spring MVC环境下混合使用Reactor(Mono/Flux)时,WebFlux的WebFilter不会生效,且不能通过@EnableWebFlux启用WebFlux栈(会与MVC冲突)。可以通过以下方式实现全局注入请求上下文到Reactor的Context中:

1. 替换WebFilter为Spring MVC过滤器

创建基于OncePerRequestFilter的MVC过滤器,通过Reactor钩子为所有返回的Reactive流注入请求信息:

import org.springframework.web.filter.OncePerRequestFilter;
import reactor.core.publisher.Operators;
import reactor.util.context.Context;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class ReactiveRequestContextMvcFilter extends OncePerRequestFilter {
    public static final String REQUEST_CONTEXT_KEY = "MVC_HTTP_REQUEST";

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        // 注册Reactor钩子,为所有后续的Mono/Flux注入请求上下文
        var hook = Operators.onEachOperator("mvc-request-context",
                operator -> operator.transformDeferredContextual((mono, ctx) ->
                        mono.subscriberContext(ctx.put(REQUEST_CONTEXT_KEY, request))));

        try {
            filterChain.doFilter(request, response);
        } finally {
            // 清理钩子,避免内存泄漏
            Operators.resetOnEachOperator("mvc-request-context", hook);
        }
    }
}

2. 注册MVC过滤器

通过配置类将过滤器注册到Spring MVC容器:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.filter.OncePerRequestFilter;

@Configuration
public class MvcConfig {
    @Bean
    public OncePerRequestFilter reactiveRequestContextMvcFilter() {
        return new ReactiveRequestContextMvcFilter();
    }
}

3. 在控制器中获取上下文请求

使用Mono.deferContextual从Reactor Context中取出请求对象,进而获取请求头构建认证上下文:

@GetMapping("/{id}")
public Mono<String> doSomething(@PathVariable("id") Long id) {
    return Mono.deferContextual(ctx -> {
        HttpServletRequest request = ctx.get(ReactiveRequestContextMvcFilter.REQUEST_CONTEXT_KEY);
        // 从请求头获取认证信息
        String authHeader = request.getHeader("Authorization");
        
        // 执行异步密集型任务
        return Mono.fromCallable(() -> {
            // 业务逻辑处理
            return "Processed task with auth: " + authHeader;
        });
    });
}

关键说明

  • 为什么不用WebFilter:WebFilter是WebFlux栈的组件,Spring MVC的DispatcherServlet不会加载和执行它,因此必须使用MVC原生的OncePerRequestFilter。
  • 为什么不能启用WebFlux:Spring MVC和WebFlux是两套独立的Web栈,同时启用会触发容器冲突报错,渐进式迁移时应保持MVC环境不变。
  • Reactor Context的优势:相较于ThreadLocal,Reactor Context与订阅者绑定,在异步线程切换时不会丢失上下文,符合Reactive编程范式。

内容的提问来源于stack exchange,提问作者mpartan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 17:30:47