nest.js上手之路


初識 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.js, Node.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,再到統一接口格式、完成接口參數驗證


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM