Spring GraphQL集成WebMvc时如何可靠传递请求头到DataFetcher
你当前通过GraphQLContext传递授权令牌的方案是Spring GraphQL官方推荐的标准实现,完全可以解决WebMvc场景下DataFetcher线程切换导致的RequestContextHolder取值失效问题,比直接依赖RequestContextHolder的实现稳定得多。
针对你代码中的疑问逐一解答:
@QueryMapping方法中注入HttpServletRequest取请求头是安全的@QueryMapping的执行阶段处于原始Web请求的处理线程中,Spring MVC注入的HttpServletRequest是动态代理对象,会自动绑定当前线程的请求实例,这里获取authorization头的逻辑没有问题。令牌存入
GraphQLContext是最优选择GraphQLContext是和单次GraphQL查询生命周期绑定的上下文对象,会自动在所有DataFetcher之间传递,不受线程切换的影响。不管@SchemaMapping方法运行在哪个线程,只要注入GraphQLContext就能拿到你存入的令牌,完全不需要处理ThreadLocal的跨线程传播问题。为什么
ThreadLocalAccessor在WebMvc下不生效
Spring GraphQL的ThreadLocal上下文传播能力目前仅适配了WebFlux的响应式调度体系,WebMvc的异步场景下要实现ThreadLocal传递需要额外配置线程池的装饰器,完全没有必要,用GraphQLContext的方案更简单也不存在ThreadLocal内存泄漏的风险。
可选优化方案
如果你不想每个@QueryMapping都手动写存令牌的逻辑,可以新增全局的GraphQlWebInterceptor统一提取令牌存入上下文:
@Component class AuthTokenGraphQlInterceptor : GraphQlWebInterceptor { override fun preHandle( webInput: WebInput, graphQLContext: GraphQLContext, container: DataFetchingEnvironment? ): Mono<WebInput> { val request = webInput.nativeRequest as HttpServletRequest request.getHeader("authorization")?.let { graphQLContext.put("AUTH_TOKEN", it) } return Mono.just(webInput) } }
配置后所有GraphQL查询都会自动把授权令牌存入上下文,不需要再在业务Controller里重复处理。
内容的提问来源于stack exchange,提问作者Ena

