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

NestJS GraphQL是否需自定义装饰器访问@Req/@Res对象

NestJS GraphQL解析器设置Cookie方案:请求/响应对象获取指南

原生@Req()/@Res()不生效的原因

NestJS原生的HTTP参数装饰器默认仅从HTTP路由执行上下文中读取对象,而GraphQL解析器运行在独立的GraphQL执行上下文,不属于常规HTTP路由处理流程,因此直接使用原生装饰器无法正确注入请求、响应对象,测试不生效属于预期行为。


问题1:GraphQL场景下是否需要自定义装饰器获取Req/Res

自定义装饰器是官方推荐的标准实践。
当前v9及以上版本的@nestjs/graphql包已内置@GqlReq()装饰器可直接用于获取请求对象,但官方未提供对应的响应对象装饰器,获取Res对象仍需通过GqlExecutionContext自定义装饰器实现,自定义装饰器可同时兼容HTTP调用、WebSocket订阅等多GraphQL传输场景。


问题2:GraphQL中正确获取响应对象的方式

你自定义装饰器里的取值逻辑是正确的,代码智能提示无法识别属性是TypeScript类型缺失导致的,不是逻辑错误。

核心取值逻辑

GraphQL执行上下文默认会将原始HTTP请求对象挂载到上下文的req属性上,而Express/Fastify等底层HTTP框架的响应对象,本身就挂载在原始请求对象的res属性上,因此ctx.getContext().req.res的写法在标准配置下完全可用。

带类型支持的装饰器实现(解决智能提示问题)

先实现请求装饰器(如果使用高版本Nest可跳过,直接用内置@GqlReq()):

import { createParamDecorator, ExecutionContext } from "@nestjs/common";
import { GqlExecutionContext } from "@nestjs/graphql";
import { Request } from "express";
// 若使用Fastify驱动,替换为fastify对应的Request类型导入

export const GqlReq = createParamDecorator(
  (_data: unknown, context: ExecutionContext): Request => {
    if (context.getType() === "http") {
      return context.switchToHttp().getRequest<Request>();
    }
    const ctx = GqlExecutionContext.create(context);
    return ctx.getContext().req;
  }
);

再实现响应装饰器,通过类型断言解决TS提示问题:

import { createParamDecorator, ExecutionContext } from "@nestjs/common";
import { GqlExecutionContext } from "@nestjs/graphql";
import { Response } from "express";
// 若使用Fastify驱动,替换为fastify对应的Response类型导入

export const GqlRes = createParamDecorator(
  (_data: unknown, context: ExecutionContext): Response => {
    if (context.getType() === "http") {
      return context.switchToHttp().getResponse<Response>();
    }
    const ctx = GqlExecutionContext.create(context);
    // 加类型断言即可解决IDE智能提示不识别的问题
    return ctx.getContext().req.res as Response;
  }
);

前置配置检查

如果取值报错,先检查GraphQL模块初始化时的context配置,必须手动透传req和res对象才能在上下文中访问到:

// app.module.ts中GraphQLModule配置示例
GraphQLModule.forRoot({
  // 其余GraphQL配置(驱动、playground、schema路径等)
  context: ({ req, res }) => ({ req, res }), // 必须显式返回req、res
})

解析器中使用示例

和HTTP场景用法一致,注入响应对象时需要加passthrough: true避免Nest判定为手动接管响应,导致解析器返回值无法正常序列化返回:

import { Query } from "@nestjs/graphql";
import { GqlReq, GqlRes } from "./common/decorators";
// 若使用高版本内置GqlReq,可直接从@nestjs/graphql导入

@Query(() => User)
async getUser(
  @GqlReq() req: RequestWithUser,
  @GqlRes({ passthrough: true }) res: Response,
): Promise<User> {
  // 直接调用cookie方法设置即可
  res.cookie("auth_token", "your_jwt_value", {
    httpOnly: true,
    maxAge: 7 * 24 * 3600 * 1000
  });
  return { email: "admin@gmail.com" };
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.03 01:27:27