2023-08-29 08:26:53 來源 : 博客園
用過express
與koa
的同學(xué),對(duì)中間件這個(gè)概念應(yīng)該非常熟悉了,中間件可以拿到Request
、Response
對(duì)象和next
函數(shù).
一般來講中間件有以下作用:
(資料圖片)
request-response
周期通過next()
調(diào)用下一個(gè)中間件如果當(dāng)前中間件沒有結(jié)束當(dāng)前request-response
周期,必須調(diào)用next()
函數(shù),否則請(qǐng)求會(huì)處于掛起狀態(tài),阻塞整個(gè)應(yīng)用中間件一般有兩種:類中間件、函數(shù)中間件
類中間件創(chuàng)建類中間件使用@Injectable()
裝飾器,并且需要實(shí)現(xiàn)NestMiddleware
接口(use
方法)
// Logger.middleware.tsimport { 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(); }}
使用類中間件類中間創(chuàng)建完之后,需要在模塊中進(jìn)行掛載,但@Module
裝飾器并沒有中間件的相關(guān)配置,我們需要讓module
類實(shí)現(xiàn)NestModule
接口,實(shí)現(xiàn)里面configure方法來進(jìn)行掛載
// user.module.tsimport { 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
方法表示掛載的是哪個(gè)中間件forRoutes
方法表示對(duì)哪個(gè)請(qǐng)求路徑起作用,這種方式與app.use(path, middleware)
作用是一樣,只針對(duì)部分路徑起作用當(dāng)給forRoutes
方法傳遞的是一個(gè)controller
控制器時(shí),那么該中間件則對(duì)整個(gè)控制器下的路徑生效比如這里傳遞的是UserController
控制器,那么針對(duì)該控制器下的路徑都會(huì)生效
forRootes
方法還能做更詳細(xì)的配置,比如可以針對(duì)特定的請(qǐng)求方法、請(qǐng)求路徑可以使用正則匹配(需要注意的是使用fastify
驅(qū)動(dòng)不能使用)export class UserModule implements NestModule { configure(consumer) { consumer .apply(LoggerMiddleware) .forRoutes({ path: "user", method: RequestMethod.GET}); }}
apply
可以同時(shí)掛載多個(gè)中間件export class UserModule implements NestModule { configure(consumer) { consumer .apply(LoggerMiddleware, aaaMiddleware, ...) .forRoutes({ path: "user", method: RequestMethod.GET}); }}
forRoutes
可以使用單個(gè)string
路徑,多個(gè)string
路徑,RouteInfo
對(duì)象,單個(gè)Controller
,多個(gè)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
需要最后調(diào)用
這種方式較為簡單,使用起來與類中間件一致
創(chuàng)建函數(shù)中間件export function LoggerMiddleware(req: Request, res: Response, next: () => void) { console.log("logger middleware", `url: ${req.url}`); next();}
使用函數(shù)中間件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) // 日志中間件
中間件其實(shí)可以用來實(shí)現(xiàn)很多功能,比如:日志系統(tǒng)、cors跨域處理、圖片防盜等...
對(duì)圖片防盜感興趣的可以看我這篇文章:你不知道的 HTTP Referer