如何在NestJS代理服务中转发请求头并避免代码重复?
针对你开发代理服务时需要重复传递Authorization头的问题,NestJS有以下几种实用工具可以解决代码冗余:
1. 使用自定义拦截器(Interceptor)
拦截器可以在请求进入控制器前统一提取Authorization头,不需要在每个控制器方法里手动获取并传递给服务。
实现步骤:
- 创建拦截器,从当前请求中提取Authorization头并附加到请求对象的自定义属性中:
// auth.interceptor.ts import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common'; import { Observable } from 'rxjs'; @Injectable() export class AuthInterceptor implements NestInterceptor { intercept(context: ExecutionContext, next: CallHandler): Observable<any> { const request = context.switchToHttp().getRequest(); const authHeader = request.headers.authorization; request.authHeader = authHeader; return next.handle(); } }
- 在控制器或全局注册拦截器,之后控制器方法直接从请求对象中获取头:
// Controller @UseInterceptors(AuthInterceptor) @Controller('items') export class ItemController { constructor(private readonly itemService: ItemService) {} @Get('GetAllItems') async getAllItems(@Req() req): Promise<AllItemsDto> { try { return await this.itemService.getAllItems(req.authHeader); } catch (e) { throw new HttpException('Error', e.status || 500); } } }
- 服务层简化,无需接收整个headers对象:
// Service public async getAllItems(authHeader: string): Promise<AllItemsDto> { const response = await this.http.axiosRef.get( `${process.env.BE_URL}/GetAllItems`, { headers: { authorization: authHeader } } ); return response.data; }
2. 配置HTTP模块的Axios拦截器
利用Nest的HttpModule给Axios添加请求拦截器,自动在转发请求时带上Authorization头,彻底省去控制器和服务层的手动传递。
实现步骤:
- 在模块中配置HttpModule时添加Axios请求拦截器,配合
AsyncLocalStorage传递当前请求的头信息:
// app.module.ts import { HttpModule } from '@nestjs/axios'; import { Module } from '@nestjs/common'; import { asyncLocalStorage } from './auth.interceptor'; @Module({ imports: [ HttpModule.registerAsync({ useFactory: () => ({ baseURL: process.env.BE_URL, interceptors: { request: [ (config) => { const authHeader = asyncLocalStorage.getStore()?.authHeader; if (authHeader) { config.headers.authorization = authHeader; } return config; }, ], }, }), }), ], }) export class AppModule {}
- 更新拦截器,用
AsyncLocalStorage存储当前请求的Authorization头:
// auth.interceptor.ts import { AsyncLocalStorage } from 'async_hooks'; import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common'; import { Observable } from 'rxjs'; export const asyncLocalStorage = new AsyncLocalStorage(); @Injectable() export class AuthInterceptor implements NestInterceptor { intercept(context: ExecutionContext, next: CallHandler): Observable<any> { const request = context.switchToHttp().getRequest(); const authHeader = request.headers.authorization; return asyncLocalStorage.run({ authHeader }, () => next.handle()); } }
此时服务层代码可完全简化:
// Service public async getAllItems(): Promise<AllItemsDto> { const response = await this.http.axiosRef.get('/GetAllItems'); return response.data; }
3. 使用自定义装饰器
如果只是想简化控制器中获取Authorization头的代码,可以自定义装饰器直接提取头信息:
实现步骤:
- 创建自定义装饰器:
// auth.decorator.ts import { createParamDecorator, ExecutionContext } from '@nestjs/common'; export const AuthHeader = createParamDecorator( (data: unknown, ctx: ExecutionContext) => { const request = ctx.switchToHttp().getRequest(); return request.headers.authorization; }, );
- 在控制器中使用该装饰器:
// Controller @Get('GetAllItems') async getAllItems(@AuthHeader() authHeader: string): Promise<AllItemsDto> { try { return await this.itemService.getAllItems(authHeader); } catch (e) { throw new HttpException('Error', e.status || 500); } }
这种方式比直接用@Headers()更简洁,避免每次都要从headers对象中提取authorization字段。
内容的提问来源于stack exchange,提问作者mark
相关产品推荐
相关产品推荐

