通用服务中如何判断GRAPHQL/HTTP上下文及获取请求头?
没问题!在NestJS生态里,你完全可以通过几种实用方式区分当前是HTTP还是GraphQL请求上下文,从而精准获取对应的test请求头。下面给你详细拆解可行方案:
方案1:用ExecutionContext直接判断请求类型
Nest的ExecutionContext是处理请求上下文的核心工具,它能直接告诉你当前请求的类型。你只需要在请求作用域服务中注入它,再通过getType()方法做判断即可:
import { Injectable, ExecutionContext, Scope } from '@nestjs/common'; @Injectable({ scope: Scope.REQUEST }) export class RequestScopedService { constructor(private readonly executionContext: ExecutionContext) {} getTestHeader(): string | undefined { const requestType = this.executionContext.getType(); // 处理HTTP请求上下文 if (requestType === 'http') { const httpRequest = this.executionContext.switchToHttp().getRequest(); return httpRequest.headers['test']; } // 处理GraphQL请求上下文 else if (requestType === 'graphql') { // GraphQL的context位于执行参数的第3位(索引为2) const gqlContext = this.executionContext.getArgByIndex(2); return gqlContext.request.headers['test']; } return undefined; } }
这个方案最直接,不需要额外配置,完全依赖Nest原生API,稳定性很高。
方案2:自定义标记区分请求类型
如果觉得每次调用ExecutionContext的方法有点繁琐,你可以给不同类型的请求打个“标记”,之后在服务里直接读取标记判断:
第一步:创建标记拦截器
分别给HTTP和GraphQL请求添加标识:
// HTTP请求标记拦截器 import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common'; import { Observable } from 'rxjs'; @Injectable() export class HttpRequestMarkerInterceptor implements NestInterceptor { intercept(context: ExecutionContext, next: CallHandler): Observable<any> { const httpRequest = context.switchToHttp().getRequest(); // 给HTTP请求打标记 httpRequest.isHttpRequest = true; return next.handle(); } } // GraphQL请求标记拦截器 import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common'; import { Observable } from 'rxjs'; import { GqlExecutionContext } from '@nestjs/graphql'; @Injectable() export class GqlRequestMarkerInterceptor implements NestInterceptor { intercept(context: ExecutionContext, next: CallHandler): Observable<any> { const gqlContext = GqlExecutionContext.create(context).getContext(); // 给GraphQL请求打标记 gqlContext.isGqlRequest = true; return next.handle(); } }
第二步:注册拦截器
在对应的模块里注册拦截器:
- HTTP模块(比如
AppModule)里注册HttpRequestMarkerInterceptor - GraphQL模块里注册
GqlRequestMarkerInterceptor
第三步:在服务中读取标记
import { Injectable, Scope, Inject } from '@nestjs/common'; import { REQUEST } from '@nestjs/core'; import { ExecutionContext } from '@nestjs/common'; @Injectable({ scope: Scope.REQUEST }) export class RequestScopedService { constructor( @Inject(REQUEST) private readonly request: any, private readonly executionContext: ExecutionContext, ) {} getTestHeader(): string | undefined { if (this.request.isHttpRequest) { return this.request.headers['test']; } // 读取GraphQL请求的标记 else if (this.executionContext.getType() === 'graphql') { const gqlContext = this.executionContext.getArgByIndex(2); return gqlContext.request.headers['test']; } return undefined; } }
这个方案适合需要频繁区分请求类型的场景,标记一次就能重复使用。
方案3:用GqlExecutionContext的转换尝试判断
Nest提供的GqlExecutionContext专门处理GraphQL上下文,如果尝试将当前上下文转换为它时抛出错误,就说明是HTTP请求:
import { Injectable, ExecutionContext, Scope } from '@nestjs/common'; import { GqlExecutionContext } from '@nestjs/graphql'; @Injectable({ scope: Scope.REQUEST }) export class RequestScopedService { constructor(private readonly executionContext: ExecutionContext) {} getTestHeader(): string | undefined { try { // 尝试转换为GraphQL上下文,成功则处理GraphQL请求 const gqlContext = GqlExecutionContext.create(this.executionContext); return gqlContext.getContext().request.headers['test']; } catch (error) { // 转换失败,说明是HTTP请求 const httpRequest = this.executionContext.switchToHttp().getRequest(); return httpRequest.headers['test']; } } }
这个方案代码最简洁,利用try-catch的逻辑区分请求类型,适合追求代码精简的场景。
需要注意的是,因为你的服务是请求作用域的,所以所有注入的上下文对象都是当前请求的专属实例,不会出现跨请求的污染问题,可以放心使用。
内容的提问来源于stack exchange,提问作者Ian Gregson
相关产品推荐
相关产品推荐

