Skip to content

中间件

中间件 个人感觉不如拦截器 和 异常捕获器好用

中间件是在路由处理器之前被调用的函数.中间件函数可以访问请求和响应对象.以及应用程序请求-响应周期中的下一个中间件函数

下一个中间件函数通常用一个名为 next 的变量表示

Nest 中的中间件默认等同于 Express 中的中间件

中间件

中间件 == 拦截器 + 异常过滤器

但是中间件只能全局和局部使用

  • 执行任何代码

  • 修改请求和响应对象

  • 结束请求-响应周期

  • 调用堆栈中的下一个中间件

  • 如果当前中间件没有结束请求-响应周期.它必须调用 next()方法将控制权传递给下一个中间件,否则请求将被挂起

代码

ts
import { AppService } from "./app.service";
import { Inject, Injectable, NestMiddleware } from "@nestjs/common";
import { Request, Response } from "express";

@Injectable()
export class AaaMiddleware implements NestMiddleware {
  @Inject(AppService)
  private readonly appService: AppService;

  use(req: Request, res: Response, next: () => void) {
    console.log("brefore");
    console.log("-------" + this.appService.getHello());
    next();
    console.log("after");
  }
}

::: waring 注意

  1. next 前面 是请求前,next 后面是请求后之星的

  2. 可以利用 Inject 被注入的 service

:::

挂载

  • 模块文件中挂载
ts
import {
  Module,
  NestModule,
  MiddlewareConsumer,
  RequestMethod,
} from "@nestjs/common";
import { Test1Service } from "./test1.service";
import { Test1Controller } from "./test1.controller";
import { Test1Middleware } from "./test1.middleware";
@Module({
  controllers: [Test1Controller],
  providers: [Test1Service],
})
export class Test1Module {
  configure(consumer: MiddlewareConsumer) {
    consumer
      .apply(Test1Middleware)
      .forRoutes({ path: "test1*path", method: RequestMethod.GET });
  }
}

这里就是匹配 test1 后面的所有路由 并且 方法是 GET 方法

next 与 装饰器 @Next 区别

  • middleware 的 next 参数就是调用下一个 middleware 的,这个很好理解。

  • 而 @Next 装饰器是调用下一个 handler 的:

举例如下

这样他会相应第二个 返回 hello2

与拦截器的不同

  • 拦截器里面能获取到 class 和 handler() 但是中间件不行

全局中间件

新建中间件文件

名字是 global.middleware.ts

这里面实现了 验证和捕获异常中间件

ts
import { Injectable, NestMiddleware } from "@nestjs/common";
import { Request, Response } from "express";
@Injectable()
export class GlobalMiddleware implements NestMiddleware {
  use(req: Request, res: Response, next: () => void) {
    console.log("请求前");
    if (req.headers["authorization"]) {
      try {
        next();
      } catch (e) {
        res.send({
          code: 500,
          message: "服务器错误",
          data: null,
        });
        return;
      }
    } else {
      res.status(401).send({
        code: 401,
        message: "未授权3",
        data: null,
      });
    }
  }
}

挂载到全局

  • 要是多个 就在apply(,,,)以逗号分开
ts
import { MiddlewareConsumer, Module, NestModule } from "@nestjs/common";
import { GlobalMiddleware } from "./global/middleware/global.middleware";
import { LoginModule } from "./Login/login.module";
@Module({
  imports: [LoginModule],
  controllers: [],
  providers: [],
})
export class AppModule implements NestModule {
  configure(consumer: MiddlewareConsumer) {
    consumer.apply(GlobalMiddleware).forRoutes("*"); // apply middleware to all routes
  }
}

挂载到各个模块下面的modules,就仅仅对各个模块使用

局部中间件

排除

  • exclude 排除路由 这样里面的都不执行这个中间件

exclude 通过path和method 路径和请求方式必须都一样才会排除

ts
// logins 模块
import {
  MiddlewareConsumer,
  Module,
  NestModule,
  RequestMethod,
} from "@nestjs/common";
import { LoginController } from "./controller/login.controller";
import { LoginService } from "./service/login.service";
import { LoginMiddleware } from "./middleware/login.middleware";
@Module({
  imports: [],
  controllers: [LoginController],
  providers: [LoginService],
  exports: [],
})
export class LoginModule implements NestModule {
  configure(consumer: MiddlewareConsumer) {
    consumer
      .apply(LoginMiddleware)
      .exclude({ path: "logins/test2", method: RequestMethod.GET })
      .forRoutes("logins");
  }
}

只在某个路由使用

路径和 请求方法必须完全匹配才行

ts
import {
  MiddlewareConsumer,
  Module,
  NestModule,
  RequestMethod,
} from "@nestjs/common";
import { LoginController } from "./controller/login.controller";
import { LoginService } from "./service/login.service";
import { LoginMiddleware } from "./middleware/login.middleware";
@Module({
  imports: [],
  controllers: [LoginController],
  providers: [LoginService],
  exports: [],
})
export class LoginModule implements NestModule {
  configure(consumer: MiddlewareConsumer) {
    consumer
      .apply(LoginMiddleware)
      .forRoutes({ path: "logins/test2", method: RequestMethod.GET });
  }
}

限定控制器

ts
import {
  MiddlewareConsumer,
  Module,
  NestModule,
  RequestMethod,
} from "@nestjs/common";
import { LoginController } from "./controller/login.controller";
import { LoginService } from "./service/login.service";
import { LoginMiddleware } from "./middleware/login.middleware";
@Module({
  imports: [],
  controllers: [LoginController],
  providers: [LoginService],
  exports: [],
})
export class LoginModule implements NestModule {
  configure(consumer: MiddlewareConsumer) {
    consumer.apply(LoginMiddleware).forRoutes(LoginController);
  }
}

跨域

两种方法

  • 命令

main.ts使用命令

ts
const app = await NestFactory.create(AppModule);
app.enableCors();
await app.listen(3000);
  • 通过参数
ts
const app = await NestFactory.create(AppModule, { cors: true });
await app.listen(3000);