【NestJS系列】核心概念:Middleware中間件

前言

用過expresskoa的同學,對中間件這個概念應該非常熟悉了,中間件可以拿到RequestResponse對象和next函數.

一般來講中間件有以下作用:

  • 執行任何代碼
  • 對請求與響應攔截並改造
  • 結束request-response週期
  • 通過next()調用下一個中間件
  • 如果當前中間件沒有結束當前request-response週期,必須調用next()函數,否則請求會處於掛起狀態,阻塞整個應用

中間件一般有兩種:類中間件函數中間件

類中間件

創建類中間件

使用@Injectable()裝飾器,並且需要實現NestMiddleware接口(use方法)

// Logger.middleware.ts
import { Injectable, NestMiddleware } from "@nestjs/common";
import { Request, Response } from "express";

@Injectable()
export class LoggerMiddleware implements NestMiddleware {
    use(req: Request, res: Response, next: () => void) {
        console.log('logger middleware', `url: ${req.url}`);
        next();
    }
}

使用類中間件

類中間創建完之後,需要在模塊中進行掛載,但@Module裝飾器並沒有中間件的相關配置,我們需要讓module類實現NestModule接口,實現裏面configure方法來進行掛載

// user.module.ts
import { Module, NestModule } from '@nestjs/common';
import { UserService } from './user.service';
import { UserController } from './user.controller';
import { LoggerMiddleware } from '../middleware/Logger.middleware';
@Module({
  controllers: [UserController],
  providers: [UserService]
})
export class UserModule implements NestModule {
  configure(consumer) {
    consumer
      .apply(LoggerMiddleware)
      .forRoutes(UserController);
  }
}
  • apply方法表示掛載的是哪個中間件
  • forRoutes方法表示對哪個請求路徑起作用,這種方式與app.use(path, middleware)作用是一樣,只針對部分路徑起作用
  • 當給forRoutes方法傳遞的是一個controller控制器時,那麼該中間件則對整個控制器下的路徑生效

比如這裏傳遞的是UserController控制器,那麼針對該控制器下的路徑都會生效

  • forRootes方法還能做更詳細的配置,比如可以針對特定的請求方法、請求路徑可以使用正則匹配(需要注意的是使用fastify驅動不能使用)
export class UserModule implements NestModule {
  configure(consumer) {
    consumer
      .apply(LoggerMiddleware)
      .forRoutes({ path: 'user', method: RequestMethod.GET});
  }
}
  • apply可以同時掛載多箇中間件
export class UserModule implements NestModule {
  configure(consumer) {
    consumer
      .apply(LoggerMiddleware, aaaMiddleware, ...)
      .forRoutes({ path: 'user', method: RequestMethod.GET});
  }
}
  • forRoutes可以使用單個string路徑,多個string路徑,RouteInfo對象,單個Controller,多個Controller
export class AppModule implements NestModule {
  configure(consumer) {
    consumer
      .apply(LoggerMiddleware, NjMiddleware, ...)
      .forRoutes(UserController, NjController, ...);
  }
}
  • exclude可以用來排除不使用中間件的路徑
export class UserModule implements NestModule {
  configure(consumer) {
    consumer
      .apply(LoggerMiddleware)
      .exclude({ path: '/user/a', method: RequestMethod.GET})
      .forRoutes(UserController);
  }
}

需要注意的是forRoutes需要最後調用

函數中間件

這種方式較爲簡單,使用起來與類中間件一致

創建函數中間件

export function LoggerMiddleware(req: Request, res: Response, next: () => void) {
    console.log('logger middleware', `url: ${req.url}`);
    next();
}

使用函數中間件

export class UserModule implements NestModule {
  configure(consumer) {
    consumer
      .apply(LoggerMiddleware)
      .exclude({ path: '/user/a', method: RequestMethod.GET})
      .forRoutes(UserController);
  }
}

全局中間件

可以直接在入口文件main.ts中使用app.use來掛載中間件,這樣掛載的中間件將全局生效

app.use(LoggerMiddleware) // 日誌中間件

中間件其實可以用來實現很多功能,比如:日誌系統、cors跨域處理、圖片防盜等...

對圖片防盜感興趣的可以看我這篇文章:你不知道的 HTTP Referer

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章