關於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);
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章