NEST 全局九件套
九件套架构
- 新建一个 src/common 文件夹
bash
── src
│ ├── app.module.ts
│ ├── common
│ │ ├── globalcheck.exception.ts 管道抛出的异常
│ │ ├── globalguard.exception.ts 守卫抛出的异常
│ │ ├── global_check.filter.ts 捕捉管道抛出的异常
│ │ ├── global_guard_check.filter.ts 捕捉守卫抛出的异常
│ │ ├── global.filter.ts 全局过滤器 捕捉其他全局异常
│ │ ├── global.guard.ts 全局守卫 验证jwt 等等
│ │ ├── custom.interceptor.ts 自定义拦截器多了个custom字段.这样总的放行
│ │ ├── global.interceptor.ts 全局拦截器 返回格式化数据
│ │ └── global.pipe.ts 全局管道 验证参数等等
│ ├── main.ts
globalcheck.exception.ts
ts
export class GlobalCheckException {
message: string;
constructor(message: string) {
this.message = message;
}
}
globalguard.exception.ts
ts
export class GlobalGuardException {
message: string;
constructor(message: string) {
this.message = message;
}
}
global_check.filter.ts
- 管道使用 一般用于参数验证,或者判断用户权限 code 403
ts
/*
https://docs.nestjs.com/exception-filters#exception-filters-1
*/
import { ExceptionFilter, Catch, ArgumentsHost } from "@nestjs/common";
import { GlobalCheckException } from "./globalcheck.exception";
@Catch(GlobalCheckException)
export class GlobalExceptionsCheckFilter implements ExceptionFilter {
catch(exception: any, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse();
const request = ctx.getRequest();
const status = 200;
// 错误内容
const message =
exception instanceof GlobalCheckException
? exception.message
: exception.stack;
response.status(status).json({
code: 403,
data: JSON.parse(message),
message: "操作失败",
});
}
}
global_guard_check.filter.ts
- 守卫使用 一般用于 token 验证,code 401
ts
/*
https://docs.nestjs.com/exception-filters#exception-filters-1
*/
import { ExceptionFilter, Catch, ArgumentsHost } from "@nestjs/common";
import { GlobalGuardException } from "./globalguard.exception";
@Catch(GlobalGuardException)
export class GlobalGuardCheckFilter implements ExceptionFilter {
catch(exception: any, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse();
const request = ctx.getRequest();
const status = 200;
// 错误内容
const message =
exception instanceof GlobalGuardException
? exception.message
: exception.stack;
response.status(status).json({
code: 401,
data: JSON.parse(message),
message: "操作失败",
});
}
}
global.filter.ts
ts
import {
ExceptionFilter,
Catch,
ArgumentsHost,
HttpException,
HttpStatus,
} from "@nestjs/common";
@Catch()
export class GlobalExceptionsFilter implements ExceptionFilter {
catch(exception: any, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse();
const request = ctx.getRequest();
const status =
exception instanceof HttpException
? exception.getStatus()
: HttpStatus.INTERNAL_SERVER_ERROR;
const message =
exception instanceof HttpException ? exception.message : exception.stack;
response.status(status).json({
statusCode: status,
timestamp: new Date().toISOString(),
path: request.url,
message: message,
name: "验证拦截器",
});
}
}
global.guard.ts
- 主要验证 token jwt
ts
import {
CanActivate,
ExecutionContext,
Inject,
Injectable,
} from "@nestjs/common";
import { GlobalCheckException } from "./globalcheck.exception";
import { ConfigService } from "@nestjs/config";
import { JwtServiceAll } from "../modules/jwt/jwt.service";
@Injectable()
export class GlobalGuard implements CanActivate {
@Inject()
private configService: ConfigService;
@Inject()
private jwtService: JwtServiceAll;
async canActivate(context: ExecutionContext): Promise<boolean> {
//权限验证
const request = context.switchToHttp().getRequest();
// 白名单
const whiteList = this.configService.get("perm").router.whitelist;
// 验证
let item = { path: request.url, method: request.method };
const isPublic = whiteList.some((content) => {
if (content.path === item.path && content.method === item.method) {
return true;
}
});
if (isPublic) {
return true;
} else {
// 判断
const authorization = request.header("Authorization") || "";
const bearer = authorization.split(" ");
if (!bearer || bearer.length < 2) {
throw new GlobalCheckException("登录 token 错误");
}
const token = bearer[1];
try {
const info = this.jwtService.verifyToken(token);
// 我这里是解析出来后把userId赋值给request 这样控制器就拿到了
(request as any).userId = info.id; // 换成你自己的payload对应字段
return true;
} catch (e) {
const result = JSON.stringify([{ message: "token 错误" }]);
throw new GlobalCheckException(result);
}
}
}
}
custom.interceptor.ts
- 自定义拦截器 用于返回特殊值
ts
import {
Injectable,
NestInterceptor,
ExecutionContext,
CallHandler,
} from "@nestjs/common";
import { Observable } from "rxjs";
import { tap, map } from "rxjs/operators";
@Injectable()
export class CustomInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
console.log("Beforetest...");
return next.handle().pipe(
map((data) => {
console.log("Aftertest...");
let { custom, ...result } = data;
if (custom) {
return {
custom: true,
data: result.data,
code: 200,
message: "",
...result,
};
} else {
return data;
}
})
);
}
}
global.interceptor.ts
- 全局拦截器
ts
import {
Injectable,
NestInterceptor,
ExecutionContext,
CallHandler,
} from "@nestjs/common";
import { Observable } from "rxjs";
import { tap, map } from "rxjs/operators";
@Injectable()
export class GlobalInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
console.log("Before...");
return next.handle().pipe(
map((data) => {
console.log("After全局...");
let { code, message, custom, ...result } = data;
// 局部返回什么就是什么
if (custom) {
let { custom, ...result } = data;
// 取消掉custom属性
return result;
}
// 剩下的是全局返回
// 控制器里面就可以返回 {code:200,data:xxx}
let resultmessage = "";
let resultcode = code || 200;
if (resultcode == 200) {
resultmessage = "操作成功";
} else {
resultmessage = "操作失败";
}
return {
code: resultcode,
message: resultmessage,
data: result.data,
};
})
);
}
}
global.pipe.ts
- 全局管道 验证参数 抛出异常
ts
import { PipeTransform, Injectable, ArgumentMetadata } from "@nestjs/common";
import { plainToInstance } from "class-transformer";
import { validate } from "class-validator";
// 引入我自己验证的异常类
import { GlobalCheckException } from "./globalcheck.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) {
const result = [
{
message: `${errors[0].constraints[arr]}`,
field: errors[0].property,
},
];
throw new GlobalCheckException(JSON.stringify(result));
}
}
// 第二种返回所有
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 GlobalCheckException(JSON.stringify(result));
}
return value;
}
}
app.module.ts
ts
import { APP_FILTER, APP_INTERCEPTOR, APP_PIPE, APP_GUARD } from "@nestjs/core";
import { GlobalExceptionsFilter } from "./common/global.filter";
import { GlobalExceptionsCheckFilter } from "./common/global_check.filter";
import { GlobalGuardCheckFilter } from "./common/global_guard_check.filter";
import { GlobalInterceptor } from "./common/global.interceptor";
import { GlobalPipe } from "./common/global.pipe";
import { GlobalGuard } from "./common/global.guard";
import { CustomInterceptor } from "./common/custom.interceptor";
import { Module } from "@nestjs/common";
import configuration from "./config/index";
import { ConfigModule } from "@nestjs/config";
@Module({
imports: [
// 配置模块
ConfigModule.forRoot({
cache: true,
load: [configuration],
isGlobal: true,
}),
],
controllers: [],
providers: [
// 全局异常过滤器(他负责兜底 处理其他异常)
{
provide: APP_FILTER,
useClass: GlobalExceptionsFilter,
},
// 检查管道过滤器
{
provide: APP_FILTER,
useClass: GlobalExceptionsCheckFilter,
},
// 守卫过滤器
{
provide: APP_FILTER,
useClass: GlobalGuardCheckFilter,
},
// 全局统一格式拦截器
{
provide: APP_INTERCEPTOR,
useClass: GlobalInterceptor,
},
// 自定义拦截器
{
provide: APP_INTERCEPTOR,
useClass: CustomInterceptor,
},
// 全局管道
{
provide: APP_PIPE,
useClass: GlobalPipe,
},
// 全局守卫
{
provide: APP_GUARD,
useClass: GlobalGuard,
},
],
})
export class AppModule {}