Nest:深入理解中间件 middleware

关于 Next 中间件

Nest 中间件中间件是处于请求和响应周期中间的函数,类似 express 中间件,可以访问请求对象(req)、响应对象(res)、和应用程序的下一个中间件函数。

中间件的主要任务是可以执行以下操作:

  1. 执行任何代码。
  2. 修改请求和响应对象。
  3. 结束请求-响应周期。
  4. 调用堆栈中的下一个中间件函数。

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

Nest 中间件应用场景:

  • 请求日志记录:记录每个进入应用的请求的详细信息,如请求路径、方法、来源IP等,便于调试和监控。
  • 身份验证和授权:在请求继续处理之前验证用户的身份,检查用户是否有权限访问特定的路由或资源。
  • 请求数据处理:对请求中的数据进行预处理,如解析、格式化、校验等。
  • 设置响应头:为即将发送的响应设置一些通用的HTTP头,如跨域资源共享(CORS)头、安全相关的头等。
  • 性能监控:监控请求处理的时间,以便分析和优化性能。
  • 缓存:实现缓存逻辑,减少对后端服务或数据库的请求,提高应用性能。
  • 限流:控制请求的频率,防止服务被过度使用或遭受拒绝服务攻击(DDoS)。
  • 错误处理:捕获请求处理过程中的异常,进行统一的错误处理。
  • 国际化:根据请求头或其他指示来设置语言环境,实现内容的国际化。
  • API版本管理:根据请求的版本信息(如URL路径、请求头)来路由到不同版本的处理逻辑。

创建中间件

Nest 中间件可以是一个函数,也可以是一个带有 @Injectable() 装饰器,实现 NestMiddleware 接口的类:

创建 Nest 项目:

bash 复制代码
nest new middleware-test -p npm

创建 middleware:

bash 复制代码
nest g middleware logger --no-spec --flat

手动标注类型, 并在 next 前后插入一些代码:

或者是一个函数:

它们之间的区别也就在,类可以实现依赖注入。而函数不行。

使用中间件

在 AppModule 模块中,使用 configure 方法来设置中间件。你可以为整个应用、特定路由或一组路由应用中间件。

forRoutes 方法用于指定中间件应用到的路由。它可以接收多种不同类型的参数,以满足不同的路由匹配需求。

  1. 字符串路径:
    可以直接传递一个字符串,表示中间件将应用于该特定路径。
javascript 复制代码
.forRoutes('users');
  1. 路径模式(带通配符):
    可以使用通配符 * 来匹配一组路由。
javascript 复制代码
.forRoutes('users/*');
  1. 控制器类:
    可以传递一个控制器类,中间件将应用于该控制器中定义的所有路由。
javascript 复制代码
.forRoutes(UsersController);
  1. 路由对象:
    可以传递一个对象,其中包含 pathmethod 属性,用于更精确地定义中间件应用的路由和方法。
javascript 复制代码
.forRoutes({ path: 'users', method: RequestMethod.GET });
  1. 路由对象数组:
    还可以传递一个路由对象数组,以将中间件应用于多个不同的路由和方法。
javascript 复制代码
.forRoutes(
  { path: 'users', method: RequestMethod.GET },
  { path: 'users', method: RequestMethod.POST },
  { path: 'admin', method: RequestMethod.ALL }
);
  1. 控制器和方法数组:
    你可以传递一个数组,其中包含控制器类和方法,以将中间件应用于特定控制器的特定方法。
javascript 复制代码
.forRoutes({ path: 'users', method: RequestMethod.ALL }, UsersController);

使用 forRoutes 方法时,可以根据需要混合使用这些配置,以实现对中间件应用的精确控制。

创建并绑定多个中间件

绑定多个中间件,可以在 configure 方法中使用链式调用 .apply() 方法,并传入多个中间件。

我们先创建个中间件:

也可以这样写:

中间件会按照从左到右,从上到下顺序对所有路由生效,我们访问页面,看下打印结果:

创建全局中间件

全局中间件在整个应用程序中的每个路由上都会生效。

除了上面使用的 forRoutes('*'),还可以在 main.ts 文件中使用 app.use() 方法:

typescript 复制代码
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { logger } from './logger.middleware';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.use(logger); // 将 logger 函数注册为全局中间件
  await app.listen(3000);
}
bootstrap();

这种形式不能注入依赖,也不能指定路由,不建议使用。

middleware 和 interceptor 区别

Nest 的 middleware 和 interceptor 都可以在请求前后加入一些逻辑,有什么区别呢?

  • interceptor 是能从 context 里拿到目标 class 和 handler,进而通过 reflector 拿到它的 metadata 等信息的,middleware 就不可以。
  • interceptor 可以用 rxjs 操作符来组织响应处理流程,middleware 也不可以。

interceptor 更适合处理与具体业务相关的逻辑,而 middleware 适合更通用的处理逻辑。

相关推荐
码农派大星。几秒前
Spring Boot 配置文件
java·spring boot·后端
GIS程序媛—椰子22 分钟前
【Vue 全家桶】7、Vue UI组件库(更新中)
前端·vue.js
DogEgg_00128 分钟前
前端八股文(一)HTML 持续更新中。。。
前端·html
ZL不懂前端31 分钟前
Content Security Policy (CSP)
前端·javascript·面试
木舟100935 分钟前
ffmpeg重复回听音频流,时长叠加问题
前端
杜杜的man41 分钟前
【go从零单排】go中的结构体struct和method
开发语言·后端·golang
幼儿园老大*42 分钟前
走进 Go 语言基础语法
开发语言·后端·学习·golang·go
llllinuuu43 分钟前
Go语言结构体、方法与接口
开发语言·后端·golang
cookies_s_s44 分钟前
Golang--协程和管道
开发语言·后端·golang
王大锤43911 小时前
golang通用后台管理系统07(后台与若依前端对接)
开发语言·前端·golang