中间件是在路由处理程序之前调用的函数,所以在中间件函数中可以访问请求和响应。
中间件函数需要执行 next()
将控制传递给下一个中间件函数,否则请求会被挂起。
可以使用 nest g mi XXX
创建中间件。
局部中间件
nest g res user
nest g mi ajax
、编写中间件代码
import { Injectable, NestMiddleware } from '@nestjs/common';
import { NextFunction, Request, Response } from 'express';@Injectable()
export class AjaxMiddleware implements NestMiddleware {use(req: Request, res: Response, next: NextFunction) {console.log('经过中间件');next();}
}
- 注册中间件
import { MiddlewareConsumer, Module, NestModule } from '@nestjs/common';
import { UserService } from './user.service';
import { UserController } from './user.controller';
import { AjaxMiddleware } from 'src/ajax/ajax.middleware';@Module({controllers: [UserController],providers: [UserService],
})
export class UserModule implements NestModule {/* 注册中间件; 可以 implements NestModule 获取代码提示 */configure(consumer: MiddlewareConsumer) {consumer.apply(AjaxMiddleware).forRoutes('user'); // 指定要拦截的路由}
}
现在所有访问 /user/*
的请求否会被中间件拦截
除了使用 forRoutes('user')
指定路由,还能给 forRoutes()
传入配置对象作为参数
import {MiddlewareConsumer,Module,NestModule,RequestMethod,
} from '@nestjs/common';
import { UserService } from './user.service';
import { UserController } from './user.controller';
import { AjaxMiddleware } from 'src/ajax/ajax.middleware';@Module({controllers: [UserController],providers: [UserService],
})
export class UserModule implements NestModule {configure(consumer: MiddlewareConsumer) {consumer.apply(AjaxMiddleware).forRoutes({path: 'user', // 指定拦截的路由method: RequestMethod.GET, // 仅拦截 GET 请求});}
}
此外,还能直接把 controller 传入 forRoutes()
作为参数,表示拦截该 controller 里面的所有请求
import { MiddlewareConsumer, Module, NestModule } from '@nestjs/common';
import { UserService } from './user.service';
import { UserController } from './user.controller';
import { AjaxMiddleware } from 'src/ajax/ajax.middleware';@Module({controllers: [UserController],providers: [UserService],
})
export class UserModule implements NestModule {configure(consumer: MiddlewareConsumer) {// 拦截 UserController 里面的所有请求consumer.apply(AjaxMiddleware).forRoutes(UserController);}
}
若要指定多个路由应用中间件,可以给 forRoutes()
传入多个参数。
若要应用多个中间件,可以给 apply()
传入多个参数。
exclude
有时我们想从中间件中排除某些路由,可以使用 exclude()
:
consumer.apply(AjaxMiddleware).exclude({ path: 'cats', method: RequestMethod.GET },{ path: 'cats', method: RequestMethod.POST },'cats/(.*)',).forRoutes('user');
若要排除多个路由,可以给 exclude()
传入多个参数。
函数式中间件
可以发现中间件的编写非常简单,就是一个类,类里面只有一个 use
函数。所以,我们也可以直接把中间件编写成一个函数:
import { NextFunction, Request, Response } from 'express';export function ajaxMiddleware(req: Request,res: Response,next: NextFunction,
) {console.log('经过中间件');next();
}
然后就可以在别的 module 导入 ajax
并使用啦
consumer.apply(ajaxMiddleware).forRoutes('user');
全局中间件
只能使用函数式中间件作全局中间件
全局中间件的优先级比局部中间件高,会先执行
import { NextFunction, Request, Response } from 'express';const whiteList = ['/user']; // 白名单export function ajaxMiddleware(req: Request,res: Response,next: NextFunction,
) {console.log(req.originalUrl);if (whiteList.includes(req.originalUrl)) {next();} else {res.send('小黑子露出鸡脚了吧');}
}
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { ajaxMiddleware } from 'src/ajax/ajax.middleware'; // 导入函数式中间件async function bootstrap() {const app = await NestFactory.create(AppModule);app.use(ajaxMiddleware); // 使用中间件await app.listen(3000);
}
bootstrap();
第三方中间件
demo:使用 cors 处理跨域
npm i cors
(NestJS 内置了)- 下载 Ts 类型支持:
npm i @types/cors -D
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import * as cors from 'cors'; // 导入 corsasync function bootstrap() {const app = await NestFactory.create(AppModule);app.use(cors()); // 注册中间件await app.listen(3000);
}
bootstrap();