使用Joi来对egg项目进行参数校验
Joi是什么
Joi 是 hapijs 自带的数据校验模块,高度封装常用的参数校验功能. Joi文档
项目中引入Joi
将Joi挂载在app对象下, app.js
const Joi = require('@hapi/joi');
const path = require('path');
class AppBootHook {
constructor(app) {
this.app = app;
const directory = path.join(app.config.baseDir, 'app/validator');
app.Joi = Joi;
app.loader.loadToApp(
directory,
'validator'
);
}
}
module.exports = AppBootHook;
新建Joi校验文件
base_contoller文件下添加Joi拦截
const { Controller } = require('egg');
class BaseController extends Controller {
constructor(request, response, app) {
super(request, response, app);
this.options = {
//允许存在不在 schema 中的字段
allowUnknown: true,
//过滤不存在 schema 中的字段
stripUnknown: true,
//可以在检测到第一个错误时立即返回,默认false(检查全部)
abortEarly: true,
//可以尝试将值转换为所需的类型(例如,将字符串转换为数字)
convert: true,
messages: {
'any.required': '{{#label}}不能为空',
'number.base': '{{#label}}参数错误',
'string.base': '{{#label}}参数错误'
}
};
}
assert(schema, params) {
const Joi = this.app.Joi;
const result = Joi.object(schema).validate(params, this.options);
if (result.error) {
throw new Error(result.error.details[0].message);
}
}
}
module.exports = BaseController;
添加中间件进行参数拦截校验
/**
* 统一错误处理
* @param options {*}
* @param app
* @returns {errorHandler}
*/
module.exports = (options, app) => {
return async function errorHandler(ctx, next) {
try {
await next();
} catch (err) {
ctx.error = err;
let message = err.message;
if (err.status === 500) {
app.logger.error(err);
message = err.stack;
if (app.config.env === 'prod') {
message = '服务暂时不可用,正在努力修复中。';
}
}
ctx.status = err.status || 200;
ctx.body = {
code: 1,
message,
status: ctx.status
};
}
};
};
contorller使用方法
以获取主题列表接口为例
// 获取主题列表
this.assert(
{
forumId: this.app.Joi.number().required().label('版块ID')
},
this.ctx.query);