区分两种注册方式

在nestjs中我们有两种注册全局的方式,一种是通过NestFactory.create得到app实例,在通过app.useGlobalXXX的方式去注册全局的东西,比如全局拦截器,全局过滤器等。

import { NestFactory } from "@nestjs/core";
import { AppModule } from "./app.module";
import { ResultFormatInterceptor } from "@/utils/interceptor";

async function bootstrap() {
    const app = await NestFactory.create(AppModule);

    // 全局拦截器
    app.useGlobalInterceptors(new ResultFormatInterceptor());

    await app.listen(3000);
}
bootstrap();

第二种是在app.module.ts中,通过app模块的providers属性,进行注册,此时我们需要从nestjs中引入预设的全局常量名APP_XXXX,然后再进行注册。

import { Module } from "@nestjs/common";
import { JwtAuthGuard } from "./utils/guards";
import { APP_GUARD} from "@nestjs/core";

@Module({
    imports: [],
    controllers: [],
    providers: [
        {
            provide: APP_GUARD,
            useClass: JwtAuthGuard
        },
    ]
})
export class AppModule {}

那么我们如何选择合适的注册方式,还是很重要的。

在之前的文章中我们讲解了Nestjs的依赖注入,其中有这种用法:

import { ExecutionContext, Injectable, UnauthorizedException, NotFoundException } from "@nestjs/common";
import { AuthGuard } from "@nestjs/passport";
import { IS_PUBLIC_KEY } from "src/utils/decorators";
import { Reflector } from "@nestjs/core";

@Injectable()
export class JwtAuthGuard extends AuthGuard("jwt") {
    constructor(private reflector: Reflector) {
        super();
    }

    /** 验证token */
    canActivate(context: ExecutionContext): boolean | Promise<boolean> | Observable<boolean> {
        // 是否是公共路由
        const isPublic = this.reflector.getAllAndOverride<boolean>(IS_PUBLIC_KEY, [
            context.getHandler(),
            context.getClass()
        ]);
        if (isPublic) return true;
        // 校验token
        return super.canActivate(context);
    }

}

在这个全局守卫中,我们通过private reflector: Reflector注入了reflector依赖,这就意味着我们在new这个守卫的时候,是必须传入reflector参数,如果通过app.useGlobalGuards()的方式,手动实例化,我们是没办法获取到这个参数依赖的。

准确的来说也不是没办法,只是不方便。

所以我们通过在app.module.tsproviders注册为全局,此时实例化的操作交给了Nestjs去做,它就可以识别到所需要的依赖,从而正确传入参数。

所以,从这点去区分,我们就可以很好的判别,该用何种方式来实现全局注册了。

只要这个类它使用了依赖注入的方式载入依赖,那么我们就通过providers的方式注入,将实例化的操作交给Nestjs去处理。

反之,它没有使用依赖注入,那么就可以直接app.useGlobalXXX的方式实现注册。

硬要用useGlobalXXX的方式注册

这种方式也不是不行,第一是便于阅读,但是写法上会繁琐一些。

首先我们需要再app.module.ts中通过默认方式加载对应的依赖。

import { Module } from "@nestjs/common";
import { JwtAuthGuard } from "./utils/guards";

@Module({
    imports: [],
    controllers: [],
    providers: [
        JwtAuthGuard
    ]
})
export class AppModule {}

由于没有使用APP_GUARD常量的方式注册,所以它现在只是一个普通依赖。

再去main.ts中注册:

import { NestFactory } from "@nestjs/core";
import { AppModule } from "./app.module";
import { JwtAuthGuard } from "./utils/guards";

async function bootstrap() {
    const app = await NestFactory.create(AppModule);

    const jwtAuthGuard = app.get(JwtAuthGuard);
    app.useGlobalGuards(jwtAuthGuard);

    await app.listen(3000);
}
bootstrap();

我们通过get的方式取出jwtAuthGuard实例,此时它的实例化也是通过Nestjs实现的,所以它的依赖也是成功注入了的,我们再将他注册到全局即可。

当然这种方式有可能会碰到其它情况而导致不适用,但是目前本人还没有碰到这种情况,等以后遇到了再看看解决方案。

分类: Nest.js 标签: Nestjs依赖注入全局注册

评论

全部评论 2

  1. 2
    2
    Google Chrome MacOS
    有个问题,在app.module中异步注册全局jwtmoule,也通过useClass的方式全局注册JwtAuthGuard,在JwtAuthGuard中获取jwtService有时是undefined,是什么原因
    1. 木灵鱼儿
      木灵鱼儿
      FireFox Windows 10
      @2没懂,建议提供demo

目录