Nest.js 系列——nest 的生命周期与编程范式
前言
nest
服务中,其实和前端开发中类似,也是拥有生命周期的。服务在一个生命周期中结束,中间会涉及到中间件、守卫等,最后经过控制器和服务处理然后返回到前端,这样一个请求的服务生命周期结束。而且在nest
中还有一些开发的核心概念和范式,这些对于一些不是后端的小伙伴非常重要,这里本着学习的态度对这些温习一下。
nest 中涉及的编程范式
OOP
面向对象编程(OOP
)是一种编程范式,它将数据和操作数据的方法组合在一起,以便将对象视为单个实体。对象的设计包括属性和方法,属性是对象的特征,而方法是对象的行为。OOP
的主要优点是代码重用性、灵活性和可维护性。
OOP
的四个基本概念是:
- 封装(
Encapsulation
):将数据和方法组合在一起,以便将对象视为单个实体,并保护其内部状态。封装可以防止外部代码直接访问对象的数据,从而提高了代码的安全性和可维护性。 - 继承(
Inheritance
):允许创建一个新类,该类从现有类继承属性和方法。继承可以减少代码重复,并使代码更易于维护。 - 多态(
Polymorphism
):允许使用相同的方法来处理不同类型的对象。多态可以提高代码的灵活性和可扩展性。 - 抽象(
Abstraction
):将复杂的现实世界建模为类和对象,以便更好地理解和管理代码。抽象可以隐藏对象的复杂性,并使代码更易于理解和维护。
在js
中所有东西都是对象,包括数字、字符串、函数和类。js
支持OOP
,因此可以使用类和对象来编写面向对象的代码。
FP
函数式编程(FP
)是一种编程范式,它将计算视为数学函数的求值,并避免使用可变状态和可变数据。FP
的主要优点是代码可读性、可维护性和可扩展性。
FP
的基本概念是:
- 纯函数(
Pure Function
):不依赖于外部状态或数据的函数,其输出仅由输入决定。纯函数可以避免副作用和不可预测性,并提高代码的可读性和可维护性。 - 不可变性(
Immutability
):避免使用可变状态和可变数据,以便更好地控制代码的行为和状态。不可变性可以提高代码的可读性、可维护性和可扩展性。 - 高阶函数(
Higher-Order Function
):接受一个或多个函数作为参数或返回一个函数的函数。高阶函数可以提高代码的抽象级别和可复用性。
在js
中,函数是一等公民,可以像其他对象一样传递和操作。js
支持FP
,因此可以使用函数和高阶函数来编写函数式的代码。
FRP
函数响应式编程(Functional Reactive Programming,FRP
)是一种编程范式,它结合了函数式编程和响应式编程的概念。FRP
的主要思想是将数据流看作是连续的时间变化的信号,并使用函数来处理这些信号。FRP
的主要优点是代码可读性、可维护性和可扩展性。在js
中,可以使用第三方库Rxjs
来实现FRP
。
AOP
AOP(Aspect-Oriented Programming)
是一种编程范式,它的主要思想是将程序的功能分解成不同的关注点(Aspect
),然后通过横向切割(Cross-Cutting Concerns
)的方式将这些关注点分离出来。AOP
的主要优点是代码可读性、可维护性和可扩展性。使用AOP
的好处是:
- 在业务外增加新功能,解耦
- 扩展功能方便,不影响业务之间的逻辑
- 逻辑集中管理
- 更有利于代码的复用
AOP
能在不破坏封装功能的前提下,额外增加功能
IOC
控制反转(Inversion of Control,IoC
)是一种编程思想,它的主要思想是将程序的控制权从程序代码中转移到外部容器中,由容器来管理程序的生命周期和依赖关系。IoC 的主要优点是代码可读性、可维护性和可扩展性。
IOC
是一种思想&设计模式
DI
依赖注入(Dependency Injection,DI
)是一种编程思想,它的主要思想是将程序的依赖关系从程序代码中移除,由外部容器来管理程序的依赖关系。DI
的主要优点是代码可读性、可维护性和可扩展性。
DI
是IOC
的具体实现
控制反转是一种面向对象编程中的一种设计原则,用来减低计算机代码之间的耦合度,其基本思想是:借助于“第三方”实现具有依赖关系的对象之间的解耦
依赖注入是一种用于实现 ioc 的设计模式,它允许类外创建依赖对象,并通过不同的方式将这些对象提供给类。
nest 生命周期
nest 核心概念
中间件
NestJS
中的中间件是一种用于处理HTTP
请求的函数,它可以在请求到达控制器之前或之后执行一些操作。中间件可以用于实现身份验证、日志记录、错误处理等功能。在NestJS
中,中间件可以是全局的,也可以是局部的。以下是一个中间件的示例代码:
import { Injectable, NestMiddleware } from '@nestjs/common'
import { Request, Response } from 'express'
@Injectable()
export class LoggerMiddleware implements NestMiddleware {
use(req: Request, res: Response, next: Function) {
console.log('Request...')
next()
}
}
在上面的代码中,我们定义了一个名为LoggerMiddleware
的中间件类,它实现了NestMiddleware
接口。在use()
方法中,我们打印了一条日志,并调用了next()
函数,表示请求可以继续向下执行。要在应用程序中使用中间件,我们需要将其添加到模块或控制器中。以下是一个将中间件添加到模块中的示例代码:
import { Module, NestModule, MiddlewareConsumer } from '@nestjs/common'
import { AppController } from './app.controller'
import { AppService } from './app.service'
import { LoggerMiddleware } from './logger.middleware'
@Module({
imports: [],
controllers: [AppController],
providers: [AppService]
})
export class AppModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer.apply(LoggerMiddleware).forRoutes('*')
}
}
在上面的代码中,我们将LoggerMiddleware
中间件添加到了AppModule
模块中,并使用forRoutes('*')
方法指定了该中间件适用于所有路由。这样,每次请求到达控制器之前,都会先执行LoggerMiddleware
中间件中的代码。
守卫
NestJS
中的守卫(Guard)
是一种用于保护路由的机制,它可以在请求到达控制器之前或之后执行一些操作。守卫可以用于实现身份验证、权限控制、缓存等功能。在NestJS
中,守卫可以是全局的,也可以是局部的。以下是一个守卫的示例代码:
import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common'
import { Observable } from 'rxjs'
@Injectable()
export class AuthGuard implements CanActivate {
canActivate(context: ExecutionContext): boolean | Promise<boolean> | Observable<boolean> {
const request = context.switchToHttp().getRequest()
return validateRequest(request)
}
}
function validateRequest(request: Request): boolean {
// 验证请求是否合法
return true
}
在上面的代码中,我们定义了一个名为AuthGuard
的守卫类,它实现了CanActivate
接口。在canActivate()
方法中,我们获取了请求对象,并调用了validateRequest()
函数来验证请求是否合法。如果请求合法,就返回true
,否则返回false
。要在控制器中使用守卫,我们需要将守卫添加到路由上。以下是一个将守卫添加到路由上的示例代码:
import { Controller, Get, UseGuards } from '@nestjs/common';
import { AuthGuard } from './auth.guard';
@Controller()
export class AppController {
@Get()
@UseGuards(AuthGuard)
getHello(): string {
return 'Hello World!';
}
}
在上面的代码中,我们将AuthGuard
守卫添加到了路由上,并使用@UseGuards()
装饰器来指定守卫的类名。这样,每次请求到达控制器之前,都会先执行AuthGuard
守卫中的代码,以确保请求的合法性。
拦截器
NestJS
中的拦截器(Interceptor
)是一种用于处理HTTP
请求和响应的函数,它可以在请求到达控制器之前或之后执行一些操作。拦截器可以用于实现日志记录、错误处理、数据转换等功能。在NestJS
中,拦截器可以是全局的,也可以是局部的。以下是一个拦截器的示例代码:
import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common'
import { Observable } from 'rxjs'
import { tap } from 'rxjs/operators'
@Injectable()
export class LoggingInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
console.log('Before...')
const now = Date.now()
return next.handle().pipe(tap(() => console.log(`After... ${Date.now() - now}ms`)))
}
}
在上面的代码中,我们定义了一个名为LoggingInterceptor
的拦截器类,它实现了NestInterceptor
接口。在intercept()
方法中,我们打印了一条日志,并记录了当前时间。然后,我们调用了next.handle()
函数,表示请求可以继续向下执行。在请求处理完成后,我们又打印了一条日志,并计算了请求处理的时间。要在应用程序中使用拦截器,我们需要将其添加到模块或控制器中。以下是一个将拦截器添加到模块中的示例代码:
import { Module, NestModule, MiddlewareConsumer } from '@nestjs/common'
import { AppController } from './app.controller'
import { AppService } from './app.service'
import { LoggingInterceptor } from './logging.interceptor'
@Module({
imports: [],
controllers: [AppController],
providers: [AppService]
})
export class AppModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer.apply(LoggerMiddleware).forRoutes('*')
}
}
controller
NestJS
中的控制器(Controller
)是用于处理 HTTP 请求的类,它们负责处理来自客户端的请求并返回响应。控制器可以使用装饰器(Decorator
)来定义路由、请求方法、中间件等。在NestJS
中,控制器是一个普通的类,它可以使用依赖注入(Dependency Injection
)来获取其他服务(Service
)的实例。以下是一个控制器的示例代码:
import { Controller, Get } from '@nestjs/common'
import { AppService } from './app.service'
@Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
@Get()
getHello(): string {
return this.appService.getHello()
}
}
在上面的代码中,我们定义了一个名为AppController
的控制器类,它使用了@Controller()
装饰器来定义路由。在构造函数中,我们使用了依赖注入来获取AppService
的实例。在getHello()
方法中,我们调用了AppService
的getHello()
方法并返回了它的返回值。
service
service
层负责提供方法和操作,只包含业务逻辑
NestJS
中的服务(Service
)是用于处理业务逻辑的类,它们负责处理控制器(Controller
)发来的请求并返回响应。服务可以使用依赖注入(Dependency Injection
)来获取其他服务的实例。在NestJS
中,服务是一个普通的类,它可以使用@Injectable()
装饰器来标记自己是一个服务。以下是一个服务的示例代码:
import { Injectable } from '@nestjs/common';
@Injectable()
export class AppService {
getHello(): string {
return 'Hello World!';
}
}
在上面的代码中,我们定义了一个名为AppService
的服务类,它使用了@Injectable()
装饰器来标记自己是一个服务。在getHello()
方法中,我们返回了一个字符串'Hello World!'
。在控制器中,我们可以使用依赖注入来获取 AppService 的实例并调用它的方法。
过滤器
NestJS
中的过滤器(Filter
)是一种用于处理HTTP
请求和响应的函数,它可以在请求到达控制器之前或之后执行一些操作。过滤器可以用于实现数据转换、错误处理、响应格式化等功能。在NestJS
中,过滤器可以是全局的,也可以是局部的。以下是一个过滤器的示例代码:
import { ExceptionFilter, Catch, ArgumentsHost } from '@nestjs/common'
import { Request, Response } from 'express'
@Catch(HttpException)
export class HttpExceptionFilter implements ExceptionFilter {
catch(exception: HttpException, host: ArgumentsHost) {
const ctx = host.switchToHttp()
const response = ctx.getResponse<Response>()
const request = ctx.getRequest<Request>()
const status = exception.getStatus()
response.status(status).json({
statusCode: status,
timestamp: new Date().toISOString(),
path: request.url
})
}
}
在上面的代码中,我们定义了一个名为HttpExceptionFilter
的过滤器类,它实现了ExceptionFilter
接口。在catch()
方法中,我们获取了请求对象和响应对象,并将异常的状态码和请求的URL
添加到响应中。要在应用程序中使用过滤器,我们需要将其添加到模块或控制器中。以下是一个将过滤器添加到模块中的示例代码:
import { Module, NestModule, MiddlewareConsumer } from '@nestjs/common'
import { AppController } from './app.controller'
import { AppService } from './app.service'
import { HttpExceptionFilter } from './http-exception.filter'
@Module({
imports: [],
controllers: [AppController],
providers: [AppService]
})
export class AppModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer.apply(LoggerMiddleware).forRoutes('*')
}
}
在上面的代码中,我们将HttpExceptionFilter
过滤器添加到了模块中,并使用@Catch()
装饰器来指定过滤器要捕获的异常类型
小结
以上就是 nestjs 中涉及到的一些前端不太熟悉的概念,这里以学习的态度进行归纳整理,希望对你有帮助。