关于EGG项目添加Joi参数校验解决方案

使用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);

猜你喜欢

转载自www.cnblogs.com/Lewiskycc/p/12118577.html
今日推荐