如何将GraphQL请求头传递给NestJS中的Axios后续请求?
如何将GraphQL请求头传递给Axios后端请求
以下是针对你的请求链路(Angular Apollo Client → NestJS GraphQL Server → Axios 外部后端)的具体实现方案:
1. 解析器层获取请求头并传递给服务
在NestJS的GraphQL解析器中,通过@Context()装饰器获取请求上下文,提取需要传递的请求头,再传给服务层方法:
import { Query, Resolver, Context, Args } from '@nestjs/graphql'; import { UsersService } from './users.service'; import { UsersArgsDto } from './dto/users-args.dto'; import { UserDto } from './dto/user.dto'; import { Request } from 'express'; @Resolver(() => UserDto) export class UsersResolver { constructor(private readonly usersService: UsersService) {} @Query(() => [UserDto]) async users( @Args() args: UsersArgsDto, @Context() context: { req: Request }, ) { // 提取需要传递的请求头(比如Authorization) const forwardHeaders = { Authorization: context.req.headers.authorization, // 可添加其他需要传递的头,如X-Request-ID、User-Agent等 }; return this.usersService.getAllUsers(args, forwardHeaders); } }
2. 服务层接收请求头并注入Axios请求
修改你的getAllUsers方法,新增参数接收请求头,然后将其合并到Axios的请求配置中:
getAllUsers( args: UsersArgsDto, forwardHeaders: Record<string, string>, // 新增参数接收请求头 ): Observable<DataResponse<UserDto[]>> { const queryParams = new URLSearchParams(); this.getQueryFilterParams<UsersQueryFilterInput>( queryParams, args.queryFilters, ); this.getPaginationParams(queryParams, args.pagination); this.getSortingParams(queryParams, args.sort); return this.httpService .get('/users', { ...this.globalConfig, params: queryParams, headers: { ...this.globalConfig.headers, // 保留全局配置的请求头 ...forwardHeaders, // 合并从GraphQL请求传来的头 }, }) .pipe( map((data) => data.data), validateObject(DataResponse<UserDto[]>), catchError((err) => { throw err; }), ); }
3. 全局自动传递方案(可选)
如果不想每个解析器都手动传递请求头,可以用AsyncLocalStorage结合NestJS拦截器实现全局自动注入:
步骤3.1 创建请求头拦截器
import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common'; import { Observable } from 'rxjs'; import { AsyncLocalStorage } from 'async_hooks'; import { GqlExecutionContext } from '@nestjs/graphql'; @Injectable() export class RequestHeaderInterceptor implements NestInterceptor { constructor(private readonly als: AsyncLocalStorage<Record<string, string>>) {} intercept(context: ExecutionContext, next: CallHandler): Observable<any> { const gqlCtx = GqlExecutionContext.create(context); const req = gqlCtx.getContext().req; // 存储需要传递的请求头到异步本地存储 const headersToForward = { Authorization: req.headers.authorization, }; return this.als.run(headersToForward, () => next.handle()); } }
步骤3.2 注册拦截器和AsyncLocalStorage
在根模块中提供AsyncLocalStorage并注册全局拦截器:
import { Module } from '@nestjs/common'; import { APP_INTERCEPTOR } from '@nestjs/core'; import { AsyncLocalStorage } from 'async_hooks'; import { RequestHeaderInterceptor } from './request-header.interceptor'; @Module({ providers: [ AsyncLocalStorage, { provide: APP_INTERCEPTOR, useClass: RequestHeaderInterceptor, }, ], }) export class AppModule {}
步骤3.3 服务层从AsyncLocalStorage获取请求头
import { Injectable } from '@nestjs/common'; import { HttpService } from '@nestjs/axios'; import { AsyncLocalStorage } from 'async_hooks'; @Injectable() export class UsersService { constructor( private readonly httpService: HttpService, private readonly als: AsyncLocalStorage<Record<string, string>>, ) {} getAllUsers( args: UsersArgsDto, ): Observable<DataResponse<UserDto[]>> { const queryParams = new URLSearchParams(); this.getQueryFilterParams<UsersQueryFilterInput>( queryParams, args.queryFilters, ); this.getPaginationParams(queryParams, args.pagination); this.getSortingParams(queryParams, args.sort); // 从异步本地存储中获取请求头 const forwardHeaders = this.als.getStore() || {}; return this.httpService .get('/users', { ...this.globalConfig, params: queryParams, headers: { ...this.globalConfig.headers, ...forwardHeaders, }, }) .pipe( map((data) => data.data), validateObject(DataResponse<UserDto[]>), catchError((err) => { throw err; }), ); } }
注意事项
- 仅传递必要的请求头,避免泄露敏感信息
- 若涉及跨域,需在NestJS的CORS配置中添加允许接收的请求头(如
Authorization) AsyncLocalStorage需要Node.js 12.17.0及以上版本支持
内容的提问来源于stack exchange,提问作者frankfullstack
相关产品推荐
相关产品推荐

