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 适合更通用的处理逻辑。

相关推荐
桂月二二26 分钟前
探索前端开发中的 Web Vitals —— 提升用户体验的关键技术
前端·ux
Ai 编码助手1 小时前
在 Go 语言中如何高效地处理集合
开发语言·后端·golang
小丁爱养花1 小时前
Spring MVC:HTTP 请求的参数传递2.0
java·后端·spring
Channing Lewis2 小时前
什么是 Flask 的蓝图(Blueprint)
后端·python·flask
hunter2062062 小时前
ubuntu向一个pc主机通过web发送数据,pc端通过工具直接查看收到的数据
linux·前端·ubuntu
qzhqbb2 小时前
web服务器 网站部署的架构
服务器·前端·架构
刻刻帝的海角2 小时前
CSS 颜色
前端·css
浪浪山小白兔3 小时前
HTML5 新表单属性详解
前端·html·html5
轩辕烨瑾3 小时前
C#语言的区块链
开发语言·后端·golang
lee5763 小时前
npm run dev 时直接打开Chrome浏览器
前端·chrome·npm