Nest (NestJS) 是一个用于构建高效、可扩展的
Node.js
服务器端应用程序的开发框架。它利用JavaScript
的渐进增强的能力,使用并完全支持TypeScript
(仍然允许开发者使用纯 JavaScript 进行开发),并结合了 OOP (面向对象编程)、FP (函数式编程)和 FRP (函数响应式编程)。在底层,Nest 构建在强大的 HTTP 服务器框架上,例如 Express (默认),并且还可以通过配置从而使用 Fastify !
Nest 在这些常见的 Node.js 框架 (Express/Fastify) 之上提高了一个抽象级别,但仍然向开发者直接暴露了底层框架的 API。这使得开发者可以自由地使用适用于底层平台的无数的第三方模块。
NestJS
是一个基于 TypeScript 的服务器端应用程序框架。 它提供了一组丰富的工具和模块来帮助开发人员构建高效、可扩展的服务器端应用程序。这些元素可以通过依赖注入系统自动注册,并可以在整个应用程序中共享。
总的来说,NestJS
是一个功能丰富、易于使用的服务器端应用程序框架,可帮助开发人员快速构建高效、可扩展的服务器端应用程序。
一、NestJS优势
NestJS
的一些优势包括:
- 构建在现代 JavaScript 栈之上,因此使用了最新的 JavaScript 技术。
- 基于 Angular 的架构和语法,提供了强大的模块化系统和依赖注入功能。
- 基于 TypeScript,提供了强类型和静态类型检查。
- 提供了丰富的工具和模块,可用于构建各种类型的服务器端应用程序,包括 RESTful API、GraphQL API、WebSocket 服务器等。
- 提供了一组可扩展的构建块,可用于快速构建应用程序。
- 提供了与主流数据库和身份验证系统的集成。
二、IOC(控制反转 )和依赖注入DI概念
这两个概念不要搞混了,IOC其实是面向对象编程中的一种设计模式,而DI则是为了实现IOC的一种技术。
下面简单认识一下为什么需要IOC,IOC有什么好处,简单来说就是减少了固定性,通过外部传参进行控制内部本身固定的一些变量,如下例子:
在我们的代码中,经常会出现一个类依赖于另外一个类的情况,比如这样:
class Dog {
}
class Person {
private _pet
constructor () {
this._pet = new Dog()
}
}
const xiaoming = new Person()
当我们遇到类与类之间存在依赖关系时,一般会直接在类的内部创建依赖对象,这样就会导致各个类之间形成耦合,并且这种关系会随着依赖关系越来越复杂从而耦合度也会越来越高,最终造成代码的难以维护。
在上述例子中:
Person
类固定依赖于Dog
类,如果后续Person
想要依赖于其他宠物类,是无法轻易修改的。- 并且如果
Dog
类有所变化,比如其属性颜色染成了黑色,Person
类也会直接受到影响。
IOC的思想就是将类的依赖动态注入,以解决上述两个问题:
class Dog {
}
class Person {
private _pet
constructor (pet) {
this._pet = pet
}
}
const xiaohei = new Dog()
const xiaoming = new Person(xiaohei) // 将实例化的 dog 传入 person 类
这样,我们就实现了类的控制反转,同时,我们需要有一个容器来维护各个对象实例,当用户需要使用实例时,容器会自动将对象实例化给用户,这部分通常由框架处理。
这种动态注入的思想叫做依赖注入(DI, Dependency Injection),它是 IoC
的一种应用形式,把对象或依赖的实例化交给IOC
容器去处理,在NestJS
中这个容器就是NestJS
的运行时系统。当需要一个对象实例的时候,我们不需要自己手动new xxxClass()
,只需要在合适的地方对类进行注册,在需要用到的地方直接注入,容器将为我们完成new
的动作。
三、NestJs中使用方式
在Nest
中使用依赖注入一般有以下三步:
1、声明定义
使用@Injectable
装饰器来声明一个类,它表示该类可以由Nest
的IOC
容器管理
通常命名方式为XXX.service.ts
// app.service.ts
import {
Injectable } from '@nestjs/common';
@Injectable()
export class AppService {
getHello(): string {
return 'Hello jiusi';
}
}
2、声明在什么地方使用
这是依赖注入的地方,一般是在类的构造函数constructor
中注入,只有完成注入后才可以使用
// app.controller.ts
import {
Controller, Get } from '@nestjs/common';
import {
AppService } from './app.service';
@Controller()
export class AppController {
constructor(private readonly appService: AppService) {
}
@Get('/hello')
get(): string {
return this.appService.getHello();
}
}
官方把appService
称为token
,NestJS
会根据这个token
在容器中找到第1步中声明的类(这个对应关系将在第三步中进行关联注册),从而提供对应的实例,这里的实例全局唯一,只有1个!在第一次需要该实例的时候,Nest
会new
一个出来,而后会缓存起来,后序如果其它地方也注入了这个依赖,那Nest
会从缓存中拿到之前new
出来的实例供大家使用。
3、建立注入依赖与容器中类的联系
依赖注入后还需要在Module
中进行关联
import {
Module } from '@nestjs/common';
import {
AppController } from './app.controller';
import {
AppService } from './app.service';
@Module({
controllers: [AppController],
providers: [AppService],
})
export class AppModule {
}
Nest
会根据所有注入的依赖关系生成一个依赖关系图,就有点类似我们使用import
引入各个模块时也会生成一个复杂的依赖关系图。这里AppController
中依赖了AppService
,如果AppService
中还依赖其它东西也会一并放到Nest
构建的依赖关系图中,Nest
会从下到上按照依赖顺序构建出一整张依赖关系图保证所有的依赖关系正常运作。
四、AOP(Aspect Oriented Programming)
中文为面向切面编程。当一个请求打过来时,一般会经过 Controller(控制器)、Service(服务)、Repository(数据库访问) 的链路。当我们不使用AOP时,需要添加一些通用逻辑时(如日志记录、权限守卫、异常处理等等),就需要在每段请求逻辑中编写相关代码。
AOP就是在所有请求外面包裹一层切面,所有请求都会经过这个切面,然后我们就可以把上述的通用逻辑放在这个结构里,如下图:
在nestJS中实现AOP的方式有很多,比如(excepion filter过滤器、pipes管道、guards守卫、interceptors拦截器)。
五、NestJS请求流程图
- Controllers -> 处理请求
- Service -> 数据访问与核心逻辑
- Modules -> 组合所有的逻辑代码
- Pipes -> 管道–核验请求的数据
- Filters -> 过滤器–处理请求时的错误
- Guards -> 守卫–鉴权与认证
- Interceptors -> 拦截器-给请求与响应加入额外的逻辑
- Repositories -> 处理在数据库中数据
六、构建NestJs实际项目
1、项目创建
首先确定你已经安装了Node.js
, Node.js
安装会附带npx
和一个npm
包运行程序。要创建新的Nest.js
应用程序,请在终端上运行以下命令:
npm i -g @nestjs/cli // 全局安装Nest
nest new project-name // 创建项目
执行完创建项目, 会初始化下面这些文件, 并且询问你要是有什么方式来管理依赖包。
如果你有安装yarn
,可以选择yarn
,能更快一些。
注意:
Nest.js
要求Node.js
(>= 10.13.0,v13 除外), 如果你的Node.js
版本不满足要求,可以通过nvm
包管理工具安装符合要求的Node.js
版本
2、项目结构
src
├── app.controller.spec.ts
├── app.controller.ts
├── app.module.ts
├── app.service.ts
├── main.ts
app.controller.ts | 单个路由的基本控制器(Controller) |
---|---|
app.controller.spec.ts | 针对控制器的单元测试 |
app.module.ts | 应用程序的根模块(Module) |
app.service.ts | 具有单一方法的基本服务(Service) |
main.ts | 应用程序的入口文件,它使用核心函数 NestFactory 来创建 Nest 应用程序的实例。 |
3、第一个接口
前面我们已经启动了服务, 那我们怎么查看呢, 首先就是找到入口文件main.ts
import {
NestFactory } from '@nestjs/core';
import {
AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
await app.listen(3000);
}
bootstrap();
内容比较简单, 使用Nest.js
的工厂函数NestFactory
来创建了一个AppModule
实例,启动了 HTTP 侦听器,以侦听main.ts
中所定义的端口。
监听的端口号可以自定义, 如果3000端口被其他项目使用,可以更改为其他的端口号
前边看到main.ts
中也没有别的文件引入, 只有AppModule
, 打开src/app.module.ts
:
import {
Module } from '@nestjs/common';
import {
AppController } from './app.controller'