最近一段时间一直在用nestjs,写起来让人有种javaspring的感觉。Nestjs可以使用express所有的中间件,而且它还有完善的支持Typescript,配合数据库关系映射typeorm使用,可以快速写出一个接口网关。本文将介绍企业级节点框架的特点和优势。从DependencyInjection(DI)谈装饰器和注解nestjs的“洋葱模型”nestjs的特点总结在我的博客:https://github.com/forthealll...欢迎star和fork1.从dependencyinjection(DI)说到(1),Angular中的依赖注入从angular1.x开始,已经实现了依赖注入或控制反转的模式。在angular1.x中,有控制器(controller)、服务(service)、模块(module)。作者早年写过一段时间的angular1.3。下面是一个例子来说明:varmyapp=angular.module('myapp',['ui.router']);myapp.controller('test1',function($scope,$timeout){}myapp.controller('test2',function($scope,$state){}上面是angular1.3中依赖注入的一个例子,首先定义了一个名为“myapp”的模块。然后在myapp模块中定义controller控制器。myapp模块交给myapp.controller函数,具体的依赖注入流程图如下:myapp模块如何定义由它的两个controller决定,另外还依赖$scope、$timeout等服务在controller中。这样就实现了依赖注入,或者说控制反转。(2)什么是依赖注入用一个例子来解释什么是依赖注入。猫类(){}老虎类(){}动物园类(){构造函数(){this.tiger=newTiger();this.cat=newCat();}}‖在上面的例子中,我们在其构造方法中定义了Zoo、InstantiateCat和Tiger。这时候如果我们想给Zoo添加一个实例变量,比如修改Zoo类本身,比如我们现在想给Zoo类添加一个Fish类的实例变量:classFish(){}classZoo(){constructor(){this.tiger=newTiger();this.cat=newCat();this.fish=newFish();}}另外如果我们要修改Zoo实例化时,传递给Tiger和Cat类的变量也必须在Zoo类上进行修改。这种反复修改会使Zoo类不具有通用性,从而需要反复测试Zoo类的功能。我们想象将实例化过程作为参数传递给Zoo类:classZoo(){constructor(options){this.options=options;}}varzoo=newZoo({tiger:newTiger(),cat:newCat(),fish:newFish()})‖‖我们将实现过程放入参数中,传递给Zoo的构造函数,这样我们不必在Zoo类中反复修改代码。这是一个引入依赖注入的简单例子。更完整的使用依赖注入可以给Zoo类添加静态方法和静态属性:classZoo(){staticanimals=[];构造函数(选项){this.options=options;这个。初始化();}init(){let_this=this;animals.forEach(function(item){item.call(_this,options);})}staticuse(module){animals.push([...module])}}Zoo.use[Cat,Tiger,Fish];varzoo=newZoo(选项);上面提到,我们使用Zoo的静态方法use将Cat、Tiger、Fish模块注入到Zoo类中,Zoo的具体实现交给Cat、Tiger、Fish模块,以及传入的options参数构造函数。(3)nestjs中的依赖注入angular中依赖注入的思想在nestjs中也有参考,同样使用了module、controller和service。@Module({imports:[otherModule],providers:[SaveService],controllers:[SaveController,SaveExtroController]})exportclassSaveModule{}上面是nestjs中定义一个模块的方法,可以在imports属性中注入其他模块,并在providers控制器中注入需要使用的相应服务,在控制器中注入需要的控制器。2.装饰器和注解在nestjs中,typescript被完美拥抱,尤其是大量使用了装饰器和注解。装饰器和注解的理解可以参考我的文章:Typescript中的装饰器和注解。看看使用装饰器和注解后在nestjs中写业务代码是多么简单:)findAll(@Req()req,@Res()res){return'这个动作返回所有的猫';}}上面定义了两个处理url为“/cats”的控制器,为这个路由的get方法定义了findAll函数。使用get方法请求/cats时,会主动触发findAll函数。另外,在findAll函数中,通过req和res参数,也可以直接在主题中使用request和request的response。比如我们通过req获取请求的参数,通过res.send返回请求结果。3、nestjs的“洋葱模型”这里简单说一下nestjs中如何分层,也就是说请求到达服务器后如何一层一层的处理,直到请求得到响应并将结果返回给客户端。在nestjs中,在service的基础上,根据处理级别增加了中间件、异常过滤器、管道、守卫、拦截器。处理函数之间存在多层处理。上图中的逻辑就是分层处理的过程。经过分层处理的请求可以到达服务器处理函数。下面介绍一下nestjs中分层模型的具体作用。(1)、中间件nestjs中的middle和express中间件完全一样。不仅如此,我们还可以直接使用express中的中间件。例如,在我的应用程序中,我需要处理核心跨域:import*ascorsfrom'cors';asyncfunctionbootstrap(){onstapp=awaitNestFactory.create(/*创建应用的业务逻辑*/)app.use(cors({origin:'http://localhost:8080',credentials:true}));等待app.listen(3000)}bootstrap();在上面的代码中,我们可以直接通过app.use来使用coreexpress中的中间件。使服务器端支持核心跨域等。除此之外,带有nestjs的中间件也完全保留了express中中间件的特点:中间件接受response和request作为参数,可以修改请求对象request和结果返回对象response来结束对request的处理,直接返回请求的结果,也就是说可以直接在中间件中res.send等,中间件处理完后,如果没有返回请求结果,可以将中间件传递给下一个中间件处理通过下一个方法。在nestjs中,中间件和express中完全一样。除了复用express中间件,在nestjs中针对特定路由使用中间件也很方便:}}以上是在具体路由url为/cats时使用LoggerMiddleware中间件。(2)、异常过滤器异常过滤器可以捕获后端验收过程中任何阶段发生的异常,捕获异常后,将处理后的异常结果返回给客户端(如返回错误码、错误信息等)。我们可以自定义一个异常过滤器,在这个异常过滤器中,我们可以指定需要捕获哪些异常,以及这些异常应该返回什么结果等。例如,自定义过滤器用于捕获HttpException异常的例子。@Catch(HttpException)exportclassHttpExceptionFilterimplementsExceptionFilter{catch(exception:HttpException,host:ArgumentsHost){constctx=host.switchToHttp();constresponse=ctx.getResponse();constrequest=ctx.getRequest()status=exception.getStatus();response.status(status).json({statusCode:status,timestamp:newDate().toISOString(),path:request.url,});}}我们可以看到host是ArgumentsHost接口,如果实现了ArgumentsHost接口,在host中可以获取到运行环境中的信息,在http请求中可以获取request和response,还可以获取client和data信息在套接字中获得。同样,对于异常过滤器,我们可以指定在某个模块中使用,也可以指定全局使用。(3)Pipes??Pipes一般用户验证请求中的参数是否符合要求,起到验证参数的作用。例如,我们需要验证或转换请求中某些参数的类型:@Injectable()exportclassParseIntPipeimplementsPipeTransform
