在Nest.js中,可以用中间件干非常多东西,比如验证所有前端接口的token是否过期,或者如要进行统一的方法,都可以进过中间件。
中间件在Nest.js通过命令创建
nest g middleware xxx
import { Injectable, NestMiddleware } from '@nestjs/common';
@Injectable()
export class MiddlewareAllMiddleware implements NestMiddleware {
use(req: any, res: any, next: () => void) {
console.log('所有组件都进过了middlewareAll这个中间件')
next();
}
}
在中间件中req用于处理前端请求,如请求头、请求体等。
在中间件中res用于处理后端给前端发送信息,设置响应的状态码、响应头、响应体等。
在中间件中next方法用于将控制权传递给下一个中间件或路由处理器。当调用next()
时,NestJS会按照中间件的顺序执行下一个中间件或路由处理器。如果没有更多的中间件或路由处理器,请求将被结束并发送响应给客户端。
执行顺序先中间件在执行controller中的方法
配置好的中间件需要在在app.module中配置
import { MiddlewareConsumer, Module, NestModule, RequestMethod } from '@nestjs/common';
import { AppService } from './app.service';
import { MiddlewareTestController } from './middleware-test/middleware-test.controller';
import { MiddlewareTestMiddleware } from './middleware-test/middleware-test.middleware';
import { MiddlewareNewTestController } from './middleware-new-test/middleware-new-test.controller';
import { MiddlewareAllMiddleware } from './middleware-all/middleware-all.middleware';
import { MiddlewareNewTestMiddleware } from './middleware-new-test/middleware-new-test.middleware';
@Module({
imports: [],
controllers: [MiddlewareTestController, MiddlewareNewTestController],
providers: [AppService],
})
export class AppModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer
.apply(MiddlewareAllMiddleware)
.forRoutes('*')
.apply(MiddlewareTestMiddleware)
.forRoutes({
path: 'middleware-test',
method: RequestMethod.ALL
})
.apply(MiddlewareNewTestMiddleware)
.forRoutes({
path: 'middleware-new-test',
method: RequestMethod.ALL
})
}
}
在这里AppModule需要实现NestModule接口中的方法
需要通过@nestjs/common进行导入NestModule
import { NestModule } from '@nestjs/common';
点开NestModule接口可以看见
import { MiddlewareConsumer } from '../middleware/middleware-consumer.interface';
/**
* @publicApi
*/
export interface NestModule {
configure(consumer: MiddlewareConsumer): any;
}
他需要我们实现一个configure方法并且接收了MiddlewareConsumer接口定义的一些方法,同时我们也需要在app.module通过@nestjs/common引入MiddlewareConsumer
import { MiddlewareConsumer, Module, NestModule, RequestMethod } from '@nestjs/common';
然后使用consumer下的方法需要也需要给consumer进行实现接口的规范
configure(consumer: MiddlewareConsumer) {}
然后就可以使用consumer下的apply方法了,这个是consumer的接口对象
import { Type } from '../type.interface';
import { MiddlewareConfigProxy } from './middleware-config-proxy.interface';
/**
* Interface defining method for applying user defined middleware to routes.
*
* @see [MiddlewareConsumer](https://docs.nestjs.com/middleware#middleware-consumer)
*
* @publicApi
*/
export interface MiddlewareConsumer {
/**
* @param {...(Type | Function)} middleware middleware class/function or array of classes/functions
* to be attached to the passed routes.
*
* @returns {MiddlewareConfigProxy}
*/
apply(...middleware: (Type<any> | Function)[]): MiddlewareConfigProxy;
}
.apply方法
.apply方法接收创建好的middlemare实例
import { MiddlewareAllMiddleware } from './middleware-all/middleware-all.middleware';
export class AppModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer
.apply(MiddlewareAllMiddleware)
}
}
在上面.apply方法的源码中,他返回MiddlewareConfigProxy接口,这个接口返回了exclude和forRoutes方法
import { Type } from '../type.interface';
import { RouteInfo } from './middleware-configuration.interface';
import { MiddlewareConsumer } from './middleware-consumer.interface';
/**
* @publicApi
*/
export interface MiddlewareConfigProxy {
/**
* Routes to exclude from the current middleware.
*
* @param {(string | RouteInfo)[]} routes
* @returns {MiddlewareConfigProxy}
*/
exclude(...routes: (string | RouteInfo)[]): MiddlewareConfigProxy;
/**
* Attaches either routes or controllers to the current middleware.
* If you pass a controller class, Nest will attach the current middleware to every path
* defined within it.
*
* @param {(string | Type | RouteInfo)[]} routes
* @returns {MiddlewareConsumer}
*/
forRoutes(...routes: (string | Type<any> | RouteInfo)[]): MiddlewareConsumer;
}
.forRoutes
forRoutes接收多个对象,在源码中可以看到有展开运算符,每个对象需要传入path和method两个属性,
path
path需要写对应的后端controller路由,这个路由可以去执行这个中间件的方法
method
method需要写对应这个controller的那些接口可以进行执行这个中间件,需要通过@nestjs/common导入RequestMethod来配置method
import { RequestMethod } from '@nestjs/common';
RequestMethod.ALL
配置这个控制器下的所有接口都可以去执行对应的中间件
RequestMethod.GET
配置这个控制器下的GET接口可以去执行对应的中间件
RequestMethod.POST
配置这个控制器下的POST接口可以去执行对应的中间件
........
.apply
在.forRoutes方法下还可以继续.apply因为源码中
import { Type } from '../type.interface';
import { RouteInfo } from './middleware-configuration.interface';
import { MiddlewareConsumer } from './middleware-consumer.interface';
/**
* @publicApi
*/
export interface MiddlewareConfigProxy {
/**
* Routes to exclude from the current middleware.
*
* @param {(string | RouteInfo)[]} routes
* @returns {MiddlewareConfigProxy}
*/
exclude(...routes: (string | RouteInfo)[]): MiddlewareConfigProxy;
/**
* Attaches either routes or controllers to the current middleware.
* If you pass a controller class, Nest will attach the current middleware to every path
* defined within it.
*
* @param {(string | Type | RouteInfo)[]} routes
* @returns {MiddlewareConsumer}
*/
forRoutes(...routes: (string | Type<any> | RouteInfo)[]): MiddlewareConsumer;
}
forRoutes方法返回了MiddlewareConsumer 而MiddlewareConsumer正好是apply所对应的接口,从而得以继续.apply下去,这样可以进行多个middleware的配置
全部代码
讲到不到位请多包涵,博主也是新手小白
import { MiddlewareConsumer, Module, NestModule, RequestMethod } from '@nestjs/common';
import { AppService } from './app.service';
import { MiddlewareTestController } from './middleware-test/middleware-test.controller';
import { MiddlewareTestMiddleware } from './middleware-test/middleware-test.middleware';
import { MiddlewareNewTestController } from './middleware-new-test/middleware-new-test.controller';
import { MiddlewareAllMiddleware } from './middleware-all/middleware-all.middleware';
import { MiddlewareNewTestMiddleware } from './middleware-new-test/middleware-new-test.middleware';
@Module({
imports: [],
controllers: [MiddlewareTestController, MiddlewareNewTestController],
providers: [AppService],
})
export class AppModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer
.apply(MiddlewareAllMiddleware)
.forRoutes('*')
.apply(MiddlewareTestMiddleware)
.forRoutes({
path: 'middleware-test',
method: RequestMethod.ALL
})
.apply(MiddlewareNewTestMiddleware)
.forRoutes({
path: 'middleware-new-test',
method: RequestMethod.ALL
})
}
}