入门笔记
请按照官方文档初始化一个simple工程项目,按照如下步骤学习即可,如有不懂的请参考官方文档。
禁止csrf验证
根据如下步骤进行控制的创建,在执行Post操作的时候会出现invalid csrf token错误。需要禁止此特性。
创建路由
/** * @param {Egg.Application} app - egg application */module.exports = app => { const { router, controller, } = app; router.get('/', controller.home.index); // 新建资源路由 router.resources('SystemUser', '/system/user', controller.system.user);};
控制器controller.system.user,对应的是controller目录下的system目录里面的user.js文件
创建对应的控制器
const Controller = require('egg').Controller;class SystemUserController extends Controller { async index() { const { ctx, } = this; ctx.body = 'hello ! this is SystemUserController'; }}module.exports = SystemUserController;
访问地址:localhost:7001/system/user
创建可以提交数据的控制器方法
const Controller = require('egg').Controller;class SystemUserController extends Controller { async index() { const { ctx, } = this; ctx.body = 'hello ! this is SystemUserController'; } async create() { const ctx = this.ctx; const user = ctx.request.body; ctx.body = user; }}module.exports = SystemUserController;
POST方法访问网址:localhost:7001/system/user 会提示invalid csrf token错误。
关闭csrf验证
// config\config.default.js // 关闭csrf验证 config.security = { csrf: { enable: false, }, };
开启验证
在上面的例子中,我们通过表单提交了任何数据,都会回显到界面上,如果是数据需要存储或者做其他业务处理,则需要对用户输入的数据进行验证。
egg提供了egg-validate插件进行表单验证安装插件
cnpm install egg-validate --save
配置启用插件
/** @type Egg.EggPlugin */module.exports = { // had enabled by egg // static: { // enable: true, // } validate: { enable: true, package: 'egg-validate', },};
使用验证组件
首先创建一个规则,这里我们定义username是字符串而且是必须的,最大长度为8个字符。
定义password为字符串且必须,最小长度为6个字符。ctx.validate(createRule, ctx.request.body);通过上述语句进行参数检查更多规则请参考:const Controller = require('egg').Controller;// 定义本接口的请求参数的验证规则const createRule = { username: { type: 'string', required: true, max: 8, }, password: { type: 'string', required: true, min: 6, },};class SystemUserController extends Controller { async index() { const { ctx, } = this; ctx.body = 'hello ! this is SystemUserController'; } async create() { const ctx = this.ctx; // 验证输入参数是否符合预期格式 ctx.validate(createRule, ctx.request.body); const user = ctx.request.body; ctx.body = user; }}module.exports = SystemUserController;
测试
使用POSTMAN提交任意字段,则会提示Validation Failed (code: invalid_param)
如何查看具体错误信息呢。下面将定义统一错误处理的中间件进行错误处理。统一错误处理中间件
在项目的app目录中创建middleware目录,此目录中可以创建中间件。
创建错误处理中间件
'use strict';module.exports = () => { return async function errorHandler(ctx, next) { try { await next(); } catch (err) { // 控制台输出 console.error('MiddleWare errorHandler', err); // 所有的异常都在 app 上触发一个 error 事件,框架会记录一条错误日志 ctx.app.emit('error', err, ctx); // status 如果没有,则统一为500 const status = err.status || 500; // 如果是500错误,且是生产环境,则统一显示“Internal Server Error” const error = status === 500 && ctx.app.config.env === 'prod' ? 'Internal Server Error' : err; // 改变上下文状态代码 ctx.status = status; // 从 error 对象上读出各个属性,设置到响应中 ctx.body = { error, }; } };};
启用中间件
文件configconfig.default.js中
// add your middleware config here config.middleware = [];
将其修改为包含你创建的中间件
// add your middleware config here // errorHandler 统一错误处理 config.middleware = [ 'errorHandler' ]; // errorHandler 只在/api上生效 config.errorHandler = { match: '/api', };
如上所示,可以设置错误处理中间件在什么URL上面起作用。这里我们使用/api
测试路由
先使用原来的路由访问:localhost:7001/system/user
错误提示依旧变更路由:打开文件:approuter.js// router.resources('SystemUser', '/system/user', controller.system.user); router.resources('SystemUser', '/api/v1/system/user', controller.system.user);
再次访问:localhost:7001/api/v1/system/user
提示信息会变成:{"error":{"message":"Validation Failed","code":"invalid_param","errors":[{"message":"required","field":"username","code":"missing_field"},{"message":"required","field":"password","code":"missing_field"}]}}
格式化接口返回的数据结构
在上面显示错误信息中,可以看到规范的Json数据,如果开发接口,我们就需要定义统一的数据结构,以便客户端进行解析。
在API开发中,可以定义接口的标准返回格式。通过框架扩展方式定义返回数据格式是一个非常方便的方法。在app目录中创建extend目录,对egg的内置对象Helper进行扩展即可。创建Helper扩展
文件:app/extend/helper.js
'use strict';module.exports = { /** * 调用正常情况的返回数据封装 * @param {Object} ctx - context * @param {*} msg - message * @param {*} data - 数据 */ success(ctx, msg, data) { ctx.body = { code: 0, msg, data, }; ctx.status = 200; }, /** * 处理失败,处理传入的失败原因 * @param {*} ctx - context * @param {Object} res - 返回的状态数据 */ fail(ctx, res) { ctx.body = { code: res.code, msg: res.msg, data: res.data, }; ctx.status = 200; },};
改造统一错误处理
// 从 error 对象上读出各个属性,设置到响应中// ctx.body = {// error,// };// 格式化返回错误信息ctx.helper.fail(ctx, { code: status, msg: error.message, data: error.errors,});
测试
再次访问:localhost:7001/api/v1/system/user
提示信息会变成:{ "code": 422, "msg": "Validation Failed", "data": [ { "message": "required", "field": "username", "code": "missing_field" }, { "message": "required", "field": "password", "code": "missing_field" } ]}
将控制器user中的返回改为标准格式
async create() { const ctx = this.ctx; // 验证输入参数是否符合预期格式 ctx.validate(createRule, ctx.request.body); const user = ctx.request.body; // ctx.body = user; this.ctx.helper.success(this.ctx, 'ok', user);}
提交满足要求的数据,测试正确的返回数据
username testuser password 1234567890提交后将返回标准的数据格式{ "code": 0, "msg": "ok", "data": { "username": "testuser", "password": "1234567890" }}