如何在Resolver中拦截GraphQL Hotchocolate Banana Cake Pop查询?
问题原因
你直接通过IHttpContextAccessor读取不到查询内容,是因为HotChocolate中间件处理请求时已经提前消费了HTTP请求体,默认不会重置流位置,后续读取时流已经处于末尾,自然拿不到内容。且如果是BananaCakePop发起的GET查询请求,查询参数是放在URL中,读请求体本身也获取不到内容,这种直接读取HttpContext的方式本身也不是HotChocolate推荐的方案。
推荐实现方案
方案1:全局请求拦截器(适合统一拦截所有查询请求)
HotChocolate提供了原生的IHttpRequestInterceptor接口,可以直接拦截所有 incoming 的GraphQL请求,包括BananaCakePop传递的查询,无需自行处理HTTP流逻辑。
- 实现拦截器逻辑
public class GraphQLRequestInterceptor : IHttpRequestInterceptor { public async ValueTask OnCreateAsync(HttpContext context, IRequestExecutor requestExecutor, IQueryRequestBuilder requestBuilder, CancellationToken cancellationToken) { // 直接获取解析后的查询内容,自动兼容GET/POST请求、批量请求等场景 if (requestBuilder.TryGetQuery(out var query)) { string rawQuery = query.ToString(); // 此处可实现你的拦截、读取、校验逻辑 } // 若仍需要读取原始HTTP请求体,可通过如下方式读取,无需额外配置中间件 context.Request.EnableBuffering(); context.Request.Body.Position = 0; using var reader = new StreamReader(context.Request.Body, leaveOpen: true); string rawBody = await reader.ReadToEndAsync(cancellationToken); context.Request.Body.Position = 0; } }
- 注册拦截器
在你的GraphQL服务注册链式配置中添加拦截器注册即可:
services.AddGraphQLServer() .AddHttpRequestInterceptor<GraphQLRequestInterceptor>() // 添加这行注册拦截器 // 保留你原有其他配置,比如AddQueryType、AddMutationType等 ;
方案2:Resolver内直接获取当前查询
如果你只需要在特定Resolver内拿到当前查询内容,不需要全局拦截,可以直接注入HotChocolate原生的IQueryContext,无需绕IHttpContextAccessor:
public async Task<IEnumerable<Account>> MyResolver( [Service] IConfigService configService, IQueryContext queryContext) // 直接注入查询上下文 { // 直接读取当前请求的查询内容 string currentQuery = queryContext.Request.Query.ToString(); // 你的原有业务逻辑 }
硬读HttpContext的补充配置
如果你一定要坚持用IHttpContextAccessor读取原始请求体,需要在GraphQL中间件注册前添加请求体缓冲配置,允许重复读取请求流:
// 这段配置要放在app.UseGraphQL()之前 app.Use(next => context => { context.Request.EnableBuffering(); return next(context); }); app.UseGraphQL();
读取时需要主动重置流位置:
httpContext.HttpContext.Request.Body.Position = 0; using var reader = new StreamReader(httpContext.HttpContext.Request.Body, leaveOpen: true); string rawBody = await reader.ReadToEndAsync(); // 读完后记得把位置重置回0,避免影响后续中间件逻辑 httpContext.HttpContext.Request.Body.Position = 0;
内容的提问来源于stack exchange,提问作者Harobed
相关产品推荐
相关产品推荐

