egg 实战

621 阅读3分钟

1.集成swagger

npm install egg-swagger-doc-feat -s


//注意需要在app/contract 才会自动解析
//定义文件夹app/contract/index.js 对象格式  
module.exports = {
    baseRequest: {
        id: {
            type: 'string',
            description: 'id 唯一键',
            required: true,
            example: '1'
        },
    },
    baseResponse: {
        code: {
            type: 'integer',
            required: true,
            example: 0
        },
        data: {
            type: 'string',
            example: '请求成功'
        },
        errorMessage: {
            type: 'string',
            example: '请求成功'
        },
    },
};

//定义app/contract/user.js对象格式  
module.exports = {
    createUserRequest: {
        mobile: {
            type: 'string',
            required: true,
            description: '手机号',
            example: '18801731528',
            format: /^1[34578]\d{9}$/,
        },
        password: {
            type: 'string',
            required: true,
            description: '密码',
            example: '111111',
        },
        realName: {
            type: 'string',
            required: true,
            description: '姓名',
            example: 'Tom'
        },
    },
}


//config/plugin.js
//添加插件
module.exports = {
  swaggerdoc: {
    enable: true,
    package: 'egg-swagger-doc-feat',
  }
};

// config.default.js
//定义接口格式
  config.swaggerdoc = {
    dirScanner: './app/controller',
    apiInfo: {
      title: '接口',
      description: '接口 swagger-ui for egg',
      version: '1.0.0',
    },
    schemes: ['http', 'https'],
    consumes: ['application/json'],
    produces: ['application/json'],
    enableSecurity: false,
    routerMap: true,
    enable: true,
  }
 
 
//定义文档类
//app/controller/user.js
const Controller = require('egg').Controller
/**
 * @Controller 用户管理  
 */
class UserController extends Controller {
    constructor(ctx) {
        super(ctx)
    }
    /**
     * @summary 创建用户
     * @description: 创建用户,记录用户信息
     * @router post /api/user
     * @request body createUserRequest *body
     * @reponse 200 baseResponse 创建成功
     */
    async create() {
        const {ctx} = this
        // ap11p()
        // ctx.body = 'user ctrl'
        // ctx.body = this.success()
        const res = {aa:'ddd'}
        ctx.helper.success({ctx, res})
    }

}
module.exports = UserController
  
  
  //测试地址:http://localhost:7001/swagger-ui.html

2.统一异常处理

//注意需要在app/middleware文件夹下 才会自动解析
// /middleware/error_handler.js
'use strict'
module.exports = (option, app) => {
  return async function (ctx, next) {
    try {
      await next()
    } catch (err) {
      // 所有的异常都在 app 上触发一个 error 事件,框架会记录一条错误日志
      app.emit('error', err, this)
      const status = err.status || 500
      // 生产环境时 500 错误的详细错误内容不返回给客户端,因为可能包含敏感信息
      const error = status === 500 && app.config.env === 'prod' ?
        'Internal Server Error' :
        err.message
      // 从 error 对象上读出各个属性,设置到响应中
      ctx.body = {
        code: status, // 服务端自身的处理逻辑错误(包含框架错误500 及 自定义业务逻辑错误533开始 ) 客户端请求参数导致的错误(4xx开始),设置不同的状态码
        error: error
      }
      if (status === 422) {
        // ctx.body.detail = err.errors
      }
      ctx.status = 200
    }
  }
}


//注册中间件
//config/config.default.js
config.middleware = ['errorHandle']; //注意这里需要把error_handler.js 调整成驼峰命名

//在对应的Controller 故意报错
const Controller = require('egg').Controller;
class HomeController extends Controller {
  async index() {
    const { ctx } = this;
    aa() //调用没用定义的方法测试
    ctx.body = 'hi, egg';
  }
}
module.exports = HomeController;

3.通用工具类

//注意需要在app/extend文件夹下 才会自动解析
//app/extend/helper.js 

const moment = require('moment')//使用日期工具
// 处理成功响应
exports.success = ({ ctx, res = null, msg = '处理成功' }) => {
    ctx.body = {
        code: 0,
        data: res,
        msg
    }
    ctx.status = 200
}
// 格式化时间
exports.formatTime = time => moment(time).format('YYYY-MM-DD HH:mm:ss')


//测试
const Controller = require('egg').Controller
class UserController extends Controller {
    constructor(ctx) {
        super(ctx)
    }
    async create() {
        const {ctx} = this
        // ap11p()
        const res = {aa:'ddd'}
        ctx.helper.success({ctx, res})//调用继承的工具类
    }
}
module.exports = UserController

4.添加校验

//安装库
npm i egg-validate -s
//config/plugin.js
  validate: {
    enable: true,
    package: 'egg-validate'
  },
//controller/user.js
async create() { 
const { ctx, service } = this // 校验参数
ctx.validate(ctx.rule.createUserRequest) 
}

5.添加model层

//安装库
npm install egg-mongoose -s
//config/plugin.js
mongoose : { 
enable: true,
package: 'egg-mongoose',
}

// config.default.js 
config.mongoose = { url: 'mongodb://127.0.0.1:27017/xxx',
    options: { // useMongoClient: true, 
    autoReconnect: true, 
    reconnectTries: Number.MAX_VALUE, 
    bufferMaxEntries: 0, 
    }, 
}

//app/model/user.js
module.exports = app => {
    const mongoose = app.mongoose
    const UserSchema = new mongoose.Schema({
        mobile: { type: String, unique: true, required: true },
        password: { type: String, required: true },
        realName: { type: String, required: true },
        avatar: { type: String, default: 'https://1.gravatar.com/avatar/a3e54af3cb6e157e496ae430aed4f4a3?s=96&d=mm' },
        extra: { type: mongoose.Schema.Types.Mixed },
        createdAt: { type: Date, default: Date.now }
    })
    return mongoose.model('User', UserSchema)
} 

6.添加service

npm install egg-bcrypt -s

//app/service/user.js
const Service = require('egg').Service

class UserService extends Service {
  
  /**
   * 创建用户
   * @param {*} payload 
   */
  async create(payload) {
    const { ctx, service } = this
    payload.password = await this.ctx.genHash(payload.password)
    return ctx.model.User.create(payload)
  }

}
module.exports = UserService


//app/controller/user.js
const Controller = require('egg').Controller
/**
 * @Controller 用户管理  
 */
class UserController extends Controller {
    constructor(ctx) {
        super(ctx)
    }
    /**
     * @summary 创建用户
     * @description: 创建用户,记录用户信息
     * @router post /api/user
     * @request body createUserRequest *body
     * @reponse 200 baseResponse 创建成功
     */
    async create() {
        const {ctx} = this
        // ap11p()
        // ctx.body = 'user ctrl'
        // ctx.body = this.success() 
        ctx.validate(ctx.rule.createUserRequest)

        const palyload = ctx.request.body || {}

        const res = await this.service.user.create(palyload)

        // const res = {aa:'ddd'}
        ctx.helper.success({ctx, res})
    }
}
module.exports = UserController

5.基于领域模型自动初始化数据

//egg根目录新增/app.js文件
//添加钩子函数
//程序每次启动执行
async didReady() {  
    console.log('========Init Data=========')
    const ctx = await this.app.createAnonymousContext(); 
    await ctx.model.User.remove(); //每次都自动清空数据
    await ctx.service.user.create({ mobile: '13611388415', password: '111111', realName: '老夏', }) }//自动插入用户信息

6.配置跨域

config\plugin.js

//打开跨域
exports.cors = {
  enable: true,
  package: "egg-cors",
};

config\config.default.js

module.exports = (appInfo) => { 
  const config = (exports = {});
 
  config.security = {
    csrf: {
      enable: false,
      ignoreJSON: true,
    },
    domainWhiteList: ["*"], // []中放放出的白名单,*代表所有
  };
  config.cors = {
    origin: "*",
    allowMethods: "GET,HEAD,PUT,POST,DELETE,PATCH",
    credentials: true,
  };

  return {
    ...config,
    ...userConfig,
  };
};