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

如何在Spring for GraphQL的WebGraphQlInterceptor中获取HttpServletRequest

从GraphQL Kickstarter迁移到Spring for GraphQL:自定义GraphQLContext获取HttpServletRequest全量信息

核心思路

Spring for GraphQL中,WebGraphQlRequest可以通过ServerWebExchange拿到原生的HttpServletRequest,进而提取请求头、参数、自定义属性,再将这些信息注入到GraphQLContext中供后续Resolver使用。

步骤1:自定义GraphQLContext(可选,推荐)

创建自定义上下文类封装需要的请求信息,方便后续业务代码直接调用:

import graphql.GraphQLContext;
import jakarta.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;

public class CustomGraphQLContext implements GraphQLContext {
    private final Map<String, String> headers;
    private final Map<String, String> requestParams;
    private final Map<String, Object> attributes;

    public CustomGraphQLContext(HttpServletRequest request) {
        // 提取请求头
        this.headers = request.getHeaderNames()
                .asIterator()
                .collect(Collectors.toMap(
                        headerName -> headerName,
                        request::getHeader
                ));
        // 提取请求参数(单值处理,多值可调整为List<String>)
        this.requestParams = request.getParameterMap()
                .entrySet()
                .stream()
                .collect(Collectors.toMap(
                        Map.Entry::getKey,
                        entry -> entry.getValue()[0]
                ));
        // 提取请求属性
        this.attributes = new HashMap<>();
        request.getAttributeNames().asIterator()
                .forEach(attrName -> attributes.put(attrName, request.getAttribute(attrName)));
    }

    // 业务快捷方法
    public String getDebugParam() {
        return requestParams.get("debug");
    }

    public String getUsername() {
        return (String) attributes.get("security.web.username");
    }

    // 实现GraphQLContext基础方法(如需直接操作上下文Map)
    @Override
    public <T> T get(Object key) {
        if (headers.containsKey(key)) return (T) headers.get(key);
        if (requestParams.containsKey(key)) return (T) requestParams.get(key);
        return (T) attributes.get(key);
    }
}

步骤2:实现WebGraphQlInterceptor注入上下文

通过拦截器获取HttpServletRequest并初始化自定义上下文,绑定到GraphQL执行上下文:

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

public class CustomContextInterceptor implements WebGraphQlInterceptor {

    @Override
    public Mono<WebGraphQlResponse> intercept(WebGraphQlRequest request, Chain chain) {
        return request.getExchange()
                // 获取原生HttpServletRequest
                .map(exchange -> exchange.getNativeRequest(HttpServletRequest.class))
                // 初始化自定义上下文
                .map(CustomGraphQLContext::new)
                // 将上下文绑定到执行输入
                .doOnNext(context -> request.configureExecutionInput((input, builder) ->
                        builder.graphQLContext(context).build()
                ))
                // 继续执行请求链
                .then(chain.next(request));
    }
}

步骤3:注册拦截器到Spring容器

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.graphql.server.WebGraphQlInterceptor;

@Configuration
public class GraphQLConfig {

    @Bean
    public WebGraphQlInterceptor customContextInterceptor() {
        return new CustomContextInterceptor();
    }
}

步骤4:在Resolver中使用自定义上下文

方式1:通过DataFetchingEnvironment获取

import graphql.schema.DataFetchingEnvironment;
import org.springframework.graphql.data.method.annotation.QueryMapping;
import org.springframework.stereotype.Controller;

@Controller
public class DemoResolver {

    @QueryMapping
    public String hello(DataFetchingEnvironment env) {
        CustomGraphQLContext context = env.getContext();
        String debugMode = context.getDebugParam();
        String username = context.getUsername();
        return String.format("Hello %s, debug mode: %s", username, debugMode);
    }
}

方式2:直接注入上下文(Spring注解支持)

import org.springframework.graphql.data.method.annotation.GraphQLContext;
import org.springframework.graphql.data.method.annotation.QueryMapping;
import org.springframework.stereotype.Controller;

@Controller
public class DemoResolver {

    @QueryMapping
    public String hello(@GraphQLContext CustomGraphQLContext context) {
        return String.format("Hello %s, debug mode: %s", 
                context.getUsername(), context.getDebugParam());
    }
}

替代方案:使用默认上下文(无需自定义类)

如果不需要封装快捷方法,也可以直接用DefaultGraphQLContext存入键值对:

@Override
public Mono<WebGraphQlResponse> intercept(WebGraphQlRequest request, Chain chain) {
    return request.getExchange()
            .map(exchange -> exchange.getNativeRequest(HttpServletRequest.class))
            .doOnNext(servletRequest -> {
                DefaultGraphQLContext context = new DefaultGraphQLContext();
                // 存入请求头
                servletRequest.getHeaderNames().asIterator()
                        .forEach(header -> context.put(header, servletRequest.getHeader(header)));
                // 存入请求参数
                servletRequest.getParameterMap().forEach((key, values) -> context.put(key, values[0]));
                // 存入自定义属性
                context.put("username", servletRequest.getAttribute("security.web.username"));
                
                request.configureExecutionInput((input, builder) ->
                        builder.graphQLContext(context).build()
                );
            })
            .then(chain.next(request));
}

此时Resolver中通过env.getContext().get("username")即可获取对应值。

内容的提问来源于stack exchange,提问作者Mohamed Ayman Naguib

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 13:05:20