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

Java 21+Spring Boot 3.2+WebFlux下无法获取GraphQL请求头

WebFlux + Spring GraphQL 获取请求头(JWT)解决方案

核心问题说明

Spring GraphQL 不支持直接在 @QueryMapping/@MutationMapping 方法参数中传入 ServerHttpRequest 或 ServerWebExchange,这类请求作用域对象需要通过 GraphQL 上下文获取。


可行解决方案

1. 直接获取单个请求头(推荐简单场景)

使用 @ContextValue 注解直接提取指定请求头,无需手动处理请求对象:

import org.springframework.graphql.data.method.annotation.ContextValue;

@QueryMapping
public Collection<Customer> queryCustomers(
        @ContextValue("Authorization") String authHeader,
        @Argument String zipCode
) {
    // 提取JWT(去掉Bearer前缀)
    String jwt = authHeader.replaceFirst("Bearer ", "");
    // 后续业务逻辑处理
    return service.queryCustomers(zipCode);
}

2. 通过 GraphQL 上下文获取完整请求信息

如果需要更多请求细节,注入 GraphQlContext 并从中获取 ServerHttpRequest:

import org.springframework.graphql.execution.GraphQlContext;
import reactor.core.publisher.Mono;

@QueryMapping
public Mono<Collection<Customer>> queryCustomers(
        GraphQlContext context,
        @Argument String zipCode
) {
    return context.getOrEmpty(ServerHttpRequest.class)
            .map(request -> {
                String authHeader = request.getHeaders().getFirst("Authorization");
                // 解析JWT、校验权限等操作
                return service.queryCustomers(zipCode);
            })
            .orElseGet(() -> {
                // 处理无请求对象的异常场景
                return service.queryCustomers(zipCode);
            });
}

3. 全局拦截器统一处理JWT(推荐鉴权场景)

实现 WebGraphQlInterceptor 全局拦截请求,解析JWT后存入上下文,供所有Controller复用:

import org.springframework.graphql.server.WebGraphQlInterceptor;
import org.springframework.graphql.server.WebGraphQlRequest;
import org.springframework.graphql.server.WebGraphQlResponse;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;

@Component
public class JwtAuthInterceptor implements WebGraphQlInterceptor {

    @Override
    public Mono<WebGraphQlResponse> intercept(WebGraphQlRequest request, Chain chain) {
        String authHeader = request.getHeaders().getFirst("Authorization");
        if (authHeader != null && authHeader.startsWith("Bearer ")) {
            String jwt = authHeader.substring(7);
            // 验证JWT合法性,解析用户信息
            String userId = parseUserIdFromJwt(jwt);
            // 将用户信息存入上下文
            request.configureExecutionInput((input, builder) ->
                    builder.graphQLContext(ctx -> ctx.put("currentUserId", userId)).build());
        }
        return chain.next(request);
    }

    // 示例:从JWT解析用户ID的工具方法
    private String parseUserIdFromJwt(String jwt) {
        // 实际业务中使用JWT库解析,比如JJWT
        return "user123";
    }
}

然后在Controller中直接获取上下文里的用户信息:

@QueryMapping
public Collection<Customer> queryCustomers(
        @ContextValue("currentUserId") String userId,
        @Argument String zipCode
) {
    // 使用用户ID做业务逻辑处理
    return service.queryCustomersByUserIdAndZipCode(userId, zipCode);
}

为什么之前的方法失败?

  • 方法参数直接传ServerHttpRequest:Spring GraphQL的方法参数解析器仅支持特定类型(如@Argument、@ContextValue、GraphQlContext),ServerHttpRequest不在支持列表中,因此报错。
  • 构造函数注入ServerHttpRequest:ServerHttpRequest是请求作用域对象,不属于Spring容器的单例Bean,无法通过构造函数注入,必须从当前请求上下文获取。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 09:43:22