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

通用服务中如何判断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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.12 05:09:34