过滤器
作用
主要用于捕获异常,一般用于全局
默认
bash
{
"statusCode": 500,
"message": "Internal server error"
}
过滤器使用
创建一个过滤器
ts
import {
ExceptionFilter,
Catch,
ArgumentsHost,
HttpException,
HttpStatus,
} from "@nestjs/common";
import { Request, Response } from "express";
@Catch(HttpException)
export class GlobalExceptionFilter implements ExceptionFilter {
catch(exception: any, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse<Response>();
const request = ctx.getRequest<Request>();
// 状态码
const status =
exception instanceof HttpException
? exception.getStatus()
: HttpStatus.INTERNAL_SERVER_ERROR;
const message =
exception instanceof HttpException ? exception.message : exception.stack;
response.status(status).json({
code: status,
timestamp: new Date().toLocaleString(),
path: request.url,
message: message,
});
response.status(status).json();
}
}
挂载到全局
app.modules.ts 中 找到
providers 里面改变 providers 对应的就是名字
useClass 对应的就是你要改变的那个类名
ts
import { Module } from "@nestjs/common";
import { LoginModule } from "./Login/login.module";
// 过滤器
import { GlobalExceptionFilter } from "./Global/filter/global.filter";
import { APP_FILTER } from "@nestjs/core";
@Module({
imports: [LoginModule],
controllers: [],
providers: [
{
provide: APP_FILTER,
useClass: GlobalExceptionFilter,
},
],
})
export class AppModule {}
挂载到单个
- 找到你要找到的路由文件,直接挂载
ts
import {
Body,
Controller,
Delete,
Get,
HttpException,
Inject,
Param,
Patch,
Post,
UseFilters,
} from "@nestjs/common";
import { LoginService } from "../service/login.service";
import { CustomExceptionFilter } from "../../Global/filter/customfilter";
@Controller("logins")
export class LoginController {
@Inject()
private loginService: LoginService;
constructor() {}
@Get()
findAll() {
return this.loginService.findAll();
}
@Get("test")
@UseFilters(CustomExceptionFilter)
findAlltest() {
throw new HttpException("内部错误", 402);
}
}
自定义异常
顾名思义 就是我自己手动定义一个异常.然后在定义一个过滤器单独用来捕捉它
一般用在单独的模块中,比如参数验证,用户验证等等
我下面就用管道来做个说明
1.先创建一个自定义异常类
- globalcheckparams.exception.ts
ts
export class GlobalCheckParamsException {
message: string;
constructor(message?) {
this.message = message;
}
}
2.创建一个过滤器
这个过滤器就用来捕捉我这个异常
- globalcheck.filter.ts
ts
import {
ExceptionFilter,
Catch,
ArgumentsHost,
HttpStatus,
} from "@nestjs/common";
import { GlobalCheckParamsException } from "./globalcheckparams.exception";
@Catch(GlobalCheckParamsException)
export class GlobalCheckExceptionsFilter implements ExceptionFilter {
catch(exception: any, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse();
const request = ctx.getRequest();
// 我这里设置死了 200 方便前端不用飘红
const status = 200;
// 错误内容
const message =
exception instanceof GlobalCheckParamsException
? exception.message
: exception.stack;
// 返回
response.status(status).json({
code: 403,
timestamp: new Date().toLocaleString(),
path: request.url,
data: message,
message: message,
name: "验证拦截器",
});
}
}
3. 把这个过滤器挂载到全局
- app.module.ts
ts
import { GlobalCheckExceptionsFilter } from "./globalcheck.filter";
import { GlobalPipe } from "./global.pipe";
@Module({
imports: [UserModule],
controllers: [],
providers: [
{
provide: APP_FILTER,
useClass: GlobalCheckExceptionsFilter,
},
{
provide: APP_PIPE,
useClass: GlobalPipe,
},
],
})
export class AppModule {}
4.使用
- 全局管道 global.pipe 验证参数类型
ts
import { PipeTransform, Injectable, ArgumentMetadata } from "@nestjs/common";
import { plainToInstance } from "class-transformer";
import { validate } from "class-validator";
// 引入我自己验证的异常类
import { GlobalCheckParamsException } from "./globalcheckparams.exception";
@Injectable()
export class GlobalPipe implements PipeTransform {
// 校验类型
private toValidate(metatype: Function): boolean {
// 其他类型不验证
const types: Function[] = [String, Boolean, Number, Array, Object];
return !types.includes(metatype);
}
async transform(value: any, metadata: ArgumentMetadata) {
const { metatype } = metadata;
if (!metatype || !this.toValidate(metatype)) {
return value;
}
// 变成对象,把规则和值 组合成验证的对象
const object = plainToInstance(metatype, value);
// 验证 errors 是个数组
const errors = await validate(object);
if (errors.length > 0) {
// 第一种只返回第一个
if (errors.length == 1) {
for (let arr in errors[0].constraints) {
throw new GlobalCheckParamsException(`${errors[0].constraints[arr]}`);
}
}
// 第二种返回所有
let result: { message: string; field: string }[] = [];
errors.forEach((item) => {
for (let arr in item.constraints) {
result.push({
message: item.constraints[arr],
field: item.property,
});
}
});
throw new GlobalCheckParamsException(JSON.stringify(result));
}
}
}
注意
注意
- 这样每次抛出异常出来,会自动给你转化成 json 格式
- 要是绑定到路由上面.它只会总路由上面的过滤器,全局的它不在走了