• 博客创建——随笔


    初识 Nest.js

    Nest.js官网介绍:

    Nest (NestJS) 是一个用于构建高效、可扩展的 Node.js 服务器端应用程序的开发框架。它利用JavaScript 的渐进增强的能力,使用并完全支持 TypeScript (仍然允许开发者使用纯 JavaScript 进行开发),并结合了 OOP (面向对象编程)、FP (函数式编程)和 FRP (函数响应式编程)。

    在底层,Nest 构建在强大的 HTTP 服务器框架上,例如 Express (默认),并且还可以通过配置从而使用 Fastify !

    Nest 在这些常见的 Node.js 框架 (Express/Fastify) 之上提高了一个抽象级别,但仍然向开发者直接暴露了底层框架的 API。这使得开发者可以自由地使用适用于底层平台的无数的第三方模块。

    上面这段话刚开始并不能完全理解, 但是简单可以解读出来Nest.js的几个特点:

    • 原生支持TypeScript的框架
    • 可以基于Express也可以选择fastify, 如果你对Express非常熟练, 直接用它的API也是没问题的

    至于其他看不懂,就暂时放一边, 因为不影响我们入门,后面深入学习后会再来分析。

    为什么选择nest.js?

    它通过灵活使用控制反转、依赖注入和面向切面编程等设计理念,极大的规范了大型应用的架构,降低了模块之间的耦合度,从而提升了应用的开发效率。在 NodeJS 的世界里,也存在一个全面借鉴 Spring 设计思想的框架

    nest与egg简单对比

    • 都是为企业级框架和应用而生
    • Egg.js基于Koa,Nest.js基于express
    • Egg.js和Nest.js都是按照约定进行开发,Egg相比Nest约定更标准
    • 面向对象方面,Nest.js优于Egg.js

    Egg特性:

    • 高度可扩展的插件
    • 内置多进程管理
    • 基于Koa,性能优异
    • 框架稳定,测试覆盖率高

    Nest特性

    • 依赖注入容器
    • 模块化封装

    项目创建

    首先确定你已经安装了Node.jsNode.js 安装会附带npx和一个npm 包运行程序。要创建新的Nest.js 应用程序,请在终端上运行以下命令:

    npm i -g @nestjs/cli  // 全局安装Nest
    nest new project-name  // 创建项目

    执行完创建项目, 会初始化下面这些文件, 并且询问你要是有什么方式来管理依赖包:

    如果你有安装yarn,可以选择yarn,能更快一些,npm在国内安装速度会慢一些

    接下来按照提示运行项目:

    注意: Nest.js 要求 Node.js(>= 10.13.0,v13 除外), 如果你的Node.js 版本不满足要求,可以通过nvm包管理工具安装符合要求的Node.js版本
     

    项目结构

    进入项目,看到的目录结构应该是这样的:

     这里简单说明一下这些核心文件:

    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 应用程序的实例。


    第一个接口

    前面我们已经启动了服务, 那我们怎么查看呢, 首先就是找到入口文件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 中所定义的端口。

    我们打开浏览器访问http://localhost:3000地址:

     这里看到的Hello World就是接口地址http://localhost:9080返回的内容

    说明Nest.js创建项目默认就给写了一个接口例子,那就通过这个接口例子来看,我们应该怎么实现一个接口。

    前边看到mian.ts中也没有别的文件引入, 只有AppModule, 打开src/app.module.ts:

    AppModule是应用程序的根模块,根模块提供了用来启动应用的引导机制,可以包含很多功能模块。

    .mudule文件需要使用一个@Module() 装饰器的类,装饰器可以理解成一个封装好的函数,其实是一个语法糖,@Module() 装饰器接收四个属性:providerscontrollersimportsexports

    • providers:Nest.js注入器实例化的提供者(服务提供者),处理具体的业务逻辑,各个模块之间可以共享(注入器的概念后面依赖注入部分会讲解);
    • controllers:处理http请求,包括路由控制,向客户端返回响应,将具体业务逻辑委托给providers处理;
    • imports:导入模块的列表,如果需要使用其他模块的服务,需要通过这里导入;
    • exports:导出服务的列表,供其他模块导入使用。如果希望当前模块下的服务可以被其他模块共享,需要在这里配置导出;
    因为咱们平时公司技术栈是vue,会觉得面生,会写AngularJS应该比较熟悉,后端写过java也应该比较熟悉,像极了Spring boot,AngularJSSpringNest.js都是基于控制反转原则设计的,而且都使用了依赖注入的方式来解决解耦问题
     
    咱们接着看文件,在app.module.ts中,看到它引入了app.controller.tsapp.service.ts

    使用@Controller装饰器来定义控制器, @Get是请求方法的装饰器,对getHello方法进行修饰, 表示这个方法会被GET请求调用。

     

    从上面,我们可以看出使用@Injectable修饰后的 AppService, 在AppModule中注册之后,在app.controller.ts中使用,我们就不需要使用new AppService()去实例化,直接引入过来就可以用。

    至此,对于http://localhost:3000/接口返回的Hello World逻辑就算理清楚了, 在这基础上我们再详细的学习一下Nest.js中的路由使用。

    路由装饰器

    Nest.js中没有单独配置路由的地方,而是使用装饰器。Nest.js中定义了若干的装饰器用于处理路由。

    @Controller

    如每一个要成为控制器的类,都需要借助@Controller装饰器的装饰,该装饰器可以传入一个路径参数,作为访问这个控制器的主路径:

    app.controller.ts文件进行修改

     通过@Controller("api")修改这个控制器的路由前缀为api, 此时可以通过

    HTTP方法处理装饰器

    @Get@Post@Put等众多用于HTTP方法处理装饰器,经过它们装饰的方法,可以对相应的HTTP请求进行响应。同时它们可以接受一个字符串或一个字符串数组作为参数,这里的字符串可以是固定的路径,也可以是通配符。现在我们来两个简单的例子

    app.controller

    app.service

     

     

    全局路由前缀

    除了上面这些装饰器可以设置路由外, 我们还可以设置全局路由前缀, 比如给所以路由都加上/api前缀。此时需要修改main.ts

     之前在Controller声明的地址就不用写了,到此我们认识了ControllerServiceModule、路由以及一些常用的装饰器

    介绍几个nest-cli提供的几个有用的命令


    //语法
    nest g [文件类型] [文件名] [文件目录]
    

      

    创建模块 

    nest g mo posts

    创建一个 posts模块,文件目录不写,默认创建和文件名一样的posts目录,在posts目录下创建一个posts.module.ts

    执行完命令后,我们还可以发现同时在根模块app.module.ts中引入PostsModule这个模块,也在@Model装饰器的inports中引入了PostsModule

    创建控制器

    nest g co posts

    此时创建了一个posts控制器,命名为posts.controller.ts以及一个该控制器的单元测试文件

    执行完命令, 文件posts.module.ts中会自动引入PostsController,并且在@Module装饰器的controllers中注入。

    创建服务类

    nest g service posts

    创建app.service.ts文件,并且在app.module.ts文件下,@Module装饰器的providers中注入注入

    其实nest-cli提供的创建命令还有很多, 比如创建过滤器、拦截器和中间件等,可以去官网查看命令

    接口格式统一

    一般开发中是不会根据HTTP状态码来判断接口成功与失败的, 而是会根据请求返回的数据,里面加上code字段

    首先定义返回的json格式:

    {
        "code": 0,
        "message": "OK",
        "data": {
        }
    }
    

      请求失败时返回:

        "code": -1,
        "message": "我错了",
        "data": {}
    }
    

      

    拦截错误请求

    首先使用命令创建一个过滤器:

    nest g filter core/filter/http-exception

    过滤器代码实现:

    import { ArgumentsHost, Catch, ExceptionFilter, HttpException } from '@nestjs/common';
    
    @Catch(HttpException)
    export class HttpExceptionFilter implements ExceptionFilter {
      catch(exception: HttpException, host: ArgumentsHost) {
        const ctx = host.switchToHttp(); // 获取请求上下文
        const response = ctx.getResponse(); // 获取请求上下文中的 response对象
        const status = exception.getStatus(); // 获取异常状态码
    
        // 设置错误信息
        const message = exception.message
          ? exception.message
          : `${status >= 500 ? 'Service Error' : 'Client Error'}`;
        const errorResponse = {
          data: {},
          message,
          code: 200,
        };
    
        // 设置返回的状态码, 请求头,发送错误信息
        response.status(200);
        response.header('Content-Type', 'application/json; charset=utf-8');
        response.send(errorResponse);
      }
    }
    

      最后需要在main.ts中全局注册

    async function bootstrap() {
      const app = await NestFactory.create(AppModule);
      app.setGlobalPrefix('api'); // 设置全局路由前缀
      app.useGlobalFilters(new HttpExceptionFilter())
      
      await app.listen(3000);
    }
    

      

    这样对请求错误就可以统一的返回了,返回请求错误只需要抛出异常即可,比如之前的:

    throw new HttpException('抛出', 200);

     

    接下来对请求成功返回的格式进行统一的处理,可以用Nest.js的拦截器来实现。

    拦截成功的返回数据

    首先使用命令创建一个拦截器:

    nest g interceptor core/interceptor/transform
    

      拦截器代码实现:

    import { CallHandler, ExecutionContext, Injectable, NestInterceptor } from '@nestjs/common';
    import { map, Observable } from 'rxjs';
    
    @Injectable()
    export class TransformInterceptor implements NestInterceptor {
      intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
        return next.handle().pipe(
          map((data) => {
            return {
              data,
              code: 200,
              msg: '请求成功',
            };
          }),
        );
      }
    }
    

      最后和过滤器一样,在main.ts中全局注册:

    async function bootstrap() {
      const app = await NestFactory.create(AppModule);
      app.setGlobalPrefix('api'); // 设置全局路由前缀
      app.useGlobalInterceptors(new TransformInterceptor())
      app.useGlobalFilters(new HttpExceptionFilter())
      
      await app.listen(3000);
    }
    

    过滤器和拦截器实现都是三部曲:创建 > 实现 > 注册,还是很简单的

    总结

    至此我们Nest.js快速上手入门就告一段落了,文章从项目如何搭建,到实现简单的CRUD,再到统一接口格式、完成接口参数验证

  • 相关阅读:
    Linux下定时删除指定目下n天前的文件
    日期时间格式化
    sed与awk
    Linux守护进程(init.d和xinetd)
    python-Json模块
    python3 urllib模块
    linux 命令 rsync
    Linux下scp的用法
    代码块重定向
    使用exec
  • 原文地址:https://www.cnblogs.com/doudoujs/p/10167261.html
Copyright © 2020-2023  润新知