Skip to content

Nest.js 系列——nest 的生命周期与编程范式

前言

nest服务中,其实和前端开发中类似,也是拥有生命周期的。服务在一个生命周期中结束,中间会涉及到中间件、守卫等,最后经过控制器和服务处理然后返回到前端,这样一个请求的服务生命周期结束。而且在nest中还有一些开发的核心概念和范式,这些对于一些不是后端的小伙伴非常重要,这里本着学习的态度对这些温习一下。

nest 中涉及的编程范式

OOP

面向对象编程(OOP)是一种编程范式,它将数据和操作数据的方法组合在一起,以便将对象视为单个实体。对象的设计包括属性和方法,属性是对象的特征,而方法是对象的行为。OOP的主要优点是代码重用性、灵活性和可维护性。

OOP的四个基本概念是:

  1. 封装(Encapsulation):将数据和方法组合在一起,以便将对象视为单个实体,并保护其内部状态。封装可以防止外部代码直接访问对象的数据,从而提高了代码的安全性和可维护性。
  2. 继承(Inheritance):允许创建一个新类,该类从现有类继承属性和方法。继承可以减少代码重复,并使代码更易于维护。
  3. 多态(Polymorphism):允许使用相同的方法来处理不同类型的对象。多态可以提高代码的灵活性和可扩展性。
  4. 抽象(Abstraction):将复杂的现实世界建模为类和对象,以便更好地理解和管理代码。抽象可以隐藏对象的复杂性,并使代码更易于理解和维护。

js中所有东西都是对象,包括数字、字符串、函数和类。js支持OOP,因此可以使用类和对象来编写面向对象的代码。

FP

函数式编程(FP)是一种编程范式,它将计算视为数学函数的求值,并避免使用可变状态和可变数据。FP的主要优点是代码可读性、可维护性和可扩展性。

FP的基本概念是:

  1. 纯函数(Pure Function):不依赖于外部状态或数据的函数,其输出仅由输入决定。纯函数可以避免副作用和不可预测性,并提高代码的可读性和可维护性。
  2. 不可变性(Immutability):避免使用可变状态和可变数据,以便更好地控制代码的行为和状态。不可变性可以提高代码的可读性、可维护性和可扩展性。
  3. 高阶函数(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的好处是:

  1. 在业务外增加新功能,解耦
  2. 扩展功能方便,不影响业务之间的逻辑
  3. 逻辑集中管理
  4. 更有利于代码的复用
  5. AOP能在不破坏封装功能的前提下,额外增加功能

IOC

控制反转(Inversion of Control,IoC)是一种编程思想,它的主要思想是将程序的控制权从程序代码中转移到外部容器中,由容器来管理程序的生命周期和依赖关系。IoC 的主要优点是代码可读性、可维护性和可扩展性。

IOC是一种思想&设计模式

DI

依赖注入(Dependency Injection,DI)是一种编程思想,它的主要思想是将程序的依赖关系从程序代码中移除,由外部容器来管理程序的依赖关系。DI的主要优点是代码可读性、可维护性和可扩展性。

DIIOC的具体实现

控制反转是一种面向对象编程中的一种设计原则,用来减低计算机代码之间的耦合度,其基本思想是:借助于“第三方”实现具有依赖关系的对象之间的解耦

依赖注入是一种用于实现 ioc 的设计模式,它允许类外创建依赖对象,并通过不同的方式将这些对象提供给类。

nest 生命周期

nest 核心概念

中间件

NestJS中的中间件是一种用于处理HTTP请求的函数,它可以在请求到达控制器之前或之后执行一些操作。中间件可以用于实现身份验证、日志记录、错误处理等功能。在NestJS中,中间件可以是全局的,也可以是局部的。以下是一个中间件的示例代码:

typescript
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()函数,表示请求可以继续向下执行。要在应用程序中使用中间件,我们需要将其添加到模块或控制器中。以下是一个将中间件添加到模块中的示例代码:

typescript
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中,守卫可以是全局的,也可以是局部的。以下是一个守卫的示例代码:

typescript
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。要在控制器中使用守卫,我们需要将守卫添加到路由上。以下是一个将守卫添加到路由上的示例代码:

kotlin
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中,拦截器可以是全局的,也可以是局部的。以下是一个拦截器的示例代码:

typescript
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()函数,表示请求可以继续向下执行。在请求处理完成后,我们又打印了一条日志,并计算了请求处理的时间。要在应用程序中使用拦截器,我们需要将其添加到模块或控制器中。以下是一个将拦截器添加到模块中的示例代码:

typescript
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)的实例。以下是一个控制器的示例代码:

typescript
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()方法中,我们调用了AppServicegetHello()方法并返回了它的返回值。

service

service层负责提供方法和操作,只包含业务逻辑

NestJS中的服务(Service)是用于处理业务逻辑的类,它们负责处理控制器(Controller)发来的请求并返回响应。服务可以使用依赖注入(Dependency Injection)来获取其他服务的实例。在NestJS中,服务是一个普通的类,它可以使用@Injectable()装饰器来标记自己是一个服务。以下是一个服务的示例代码:

kotlin
import { Injectable } from '@nestjs/common';


@Injectable()
export class AppService {
  getHello(): string {
    return 'Hello World!';
  }
}

在上面的代码中,我们定义了一个名为AppService的服务类,它使用了@Injectable()装饰器来标记自己是一个服务。在getHello()方法中,我们返回了一个字符串'Hello World!'。在控制器中,我们可以使用依赖注入来获取 AppService 的实例并调用它的方法。

过滤器

NestJS中的过滤器(Filter)是一种用于处理HTTP请求和响应的函数,它可以在请求到达控制器之前或之后执行一些操作。过滤器可以用于实现数据转换、错误处理、响应格式化等功能。在NestJS中,过滤器可以是全局的,也可以是局部的。以下是一个过滤器的示例代码:

typescript
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添加到响应中。要在应用程序中使用过滤器,我们需要将其添加到模块或控制器中。以下是一个将过滤器添加到模块中的示例代码:

typescript
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 中涉及到的一些前端不太熟悉的概念,这里以学习的态度进行归纳整理,希望对你有帮助。

如有转载或 CV 的请标注本站原文地址