传送门
本章内容
- Nest安装与错误处理
- 自定义数据返回格式
- 自定义异常处理、错误码
安装
请确保操作系统上安装了 Node.js(>= 10.13.0)
本地环境
$ node -v
v14.15.4
$ npm -v
6.14.11
安装Nest CLI
$ npm i -g @nestjs/cli
初始化项目
$ nest new project-name
将创建 project-name
目录, 安装node模块和一些其他样板文件,并将创建一个 src
目录,目录中包含几个核心文件
src
├── app.controller.ts
├── app.module.ts
└── main.ts
运行项目
$ npm run start
神奇的事情发生了,迎面就是一堆错误
遇到错误不要慌,交友网站搜一搜:./node_modules/tapable
,哟呵,还是热乎的
大意是tapable
这个库更新了,相关webpack
版本也升级了,吧啦吧…好歹找到了解决方案(原文链接:github)
命令走一个
$ npm i @types/webpack@4.41.27
$ npm i tapable@1.1.3
再次运行启动成功,浏览器中输入:http://localhost:3000/
久违的hello world!
迷人依旧!
用户模块
不管业务需求是啥,先来个用户模块错不了,src
目录下创建文件夹modules
,使用Nest CLI生成一个user
模块,控制器以及service
$ nest g mo modules/user
$ nest g co modules/user
$ nest g s modules/user
user.controller.ts
写入如下代码
import { Controller, Get } from '@nestjs/common';
@Controller('user')
export class UserController {
@Get('sayhi')
async sayhi(): Promise<string> {
return '你好,世界';
}
}
重新运行项目,使用api调试工具访问:http://localhost:3000/user/sayhi
,符合我们的预期
数据格式
实际项目中,api接口返回的一般都是固定结构的json
对象,类似
{
"code":0,
"msg":"success",
"data":{
...
}
}
其中code
为自定义的业务错误码,比如没有权限,注册时用户名已注册等,src
目录下创建libs
文件夹,创建一个拦截器
$ nest g in libs/interceptors/data
拦截器代码
import {
Injectable,
NestInterceptor,
CallHandler,
ExecutionContext,
} from '@nestjs/common';
import { map } from 'rxjs/operators';
import { Observable } from 'rxjs';
interface Response<T> {
data: T;
}
@Injectable()
export class TransformInterceptor<T>
implements NestInterceptor<T, Response<T>> {
intercept(
context: ExecutionContext,
next: CallHandler<T>,
): Observable<Response<T>> {
return next.handle().pipe(
map((data) => {
return {
data: data ?? null,
code: 0,
message: 'success',
};
}),
);
}
}
main.ts
中全局注册
import { NestFactory } from '@nestjs/core';
import { TransformInterceptor } from './libs/interceptors/data.interceptor';
import { AppModule } from './app.module';
async function bootstrap() {
...
app.useGlobalInterceptors(new TransformInterceptor());
...
}
bootstrap();
运行程序,再次访问:http://localhost:3000/user/sayhi
{
"data": "你好,世界",
"code": 0,
"message": "success"
}
自定义异常
实际项目中,很多情况下我们需要中断程序运行,返回错误信息,创建一个过滤器
$ nest g f libs/filters/http-exception
src/libs
目录下创建enums
目录,新建error-code-enum.ts
文件,放几个错误码
export enum BusiErrorCode {
TIMEOUT = -1, // 系统繁忙
SUCCESS = 0, // 成功
PARAM_ERROR = 10000, // 请求参数错误
NOT_FOUND = 10001, // 查找的资源不存在
UN_AUTHORIZED = 20000, // 用户未登录
AUTH_FORBIDDEN = 30000, // 用户没有权限
PWD_ERROR = 40000, // 账号或者密码错误
}
libs/filters
目录下创建busi.exception.ts
文件
import { HttpException, HttpStatus } from '@nestjs/common';
import { BusiErrorCode } from '../enums/error-code-enum';
export class BusiException extends HttpException {
private _code: BusiErrorCode;
private _message: string;
constructor(
code: BusiErrorCode | number,
message: string,
statusCode: HttpStatus = HttpStatus.BAD_REQUEST,
) {
super(message, statusCode);
this._code = code;
this._message = message;
}
getErrorCode(): BusiErrorCode {
return this._code;
}
getErrorMessage(): string {
return this._message;
}
}
http-exception.filter.ts
文件中代码
import {
ArgumentsHost,
Catch,
ExceptionFilter,
HttpException,
} from '@nestjs/common';
import { BusiException } from './busi.exception';
@Catch(HttpException)
export class HttpExceptionFilter implements ExceptionFilter {
catch(exception: HttpException, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse();
const request = ctx.getRequest();
const status = exception.getStatus();
let code, message;
if (exception instanceof BusiException) {
code = exception.getErrorCode();
message = exception.getErrorMessage();
} else {
code = exception.getStatus();
message = exception.message;
}
response.status(status).json({
code,
message,
data: null,
date: new Date().toLocaleDateString(),
path: request.url,
});
}
}
main.ts
中全局注册
import { NestFactory } from '@nestjs/core';
import { TransformInterceptor } from './libs/interceptors/data.interceptor';
import { AppModule } from './app.module';
async function bootstrap() {
...
app.useGlobalFilters(new HttpExceptionFilter());
...
}
bootstrap();
修改user.controller.ts
,加入触发异常的代码
import { Controller, Get, HttpStatus } from '@nestjs/common';
import { BusiException } from '../../libs/filters/busi.exception';
import { BusiErrorCode } from '../../libs/enums/error-code-enum';
@Controller('user')
export class UserController {
...
@Get('exception')
async exception(): Promise<string> {
// throw new BusiException(BusiErrorCode.NOT_FOUND, '缺省状态码,默认触发http 400错误');
throw new BusiException(
BusiErrorCode.NOT_FOUND,
'错误:http状态正常',
HttpStatus.OK,
);
}
}
运行程序,访问:http://localhost:3000/user/exception
看起来还不错,下篇我们捣鼓TypeOrm和MySQL数据库。