uni-app 25后端api开发和前后端交互(1-50)

Posted 2019ab

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了uni-app 25后端api开发和前后端交互(1-50)相关的知识,希望对你有一定的参考价值。

1创建项目和基础配置

创建项目

安装egg.js
全局切换镜像:

npm config set registry https://registry.npm.taobao.org

我们推荐直接使用脚手架,只需几条简单指令,即可快速生成项目(npm >=6.1.0):

mkdir egg-example && cd egg-example
npm init egg --type=simple --registry https://registry.npm.taobao.org
npm i

启动项目:

npm run dev
open http://localhost:7001

关闭csrf开启跨域

安装

npm i egg-cors --save

配置插件

// {app_root}/config/plugin.js
cors:{
  enable: true,
  package: 'egg-cors',
},
config / config.default.js 目录下配置
  config.security = {
    // 关闭 csrf
    csrf: {
      enable: false,
    },
     // 跨域白名单
    domainWhiteList: [ 'http://localhost:3000' ],
  };
  // 允许跨域的方法
  config.cors = {
    origin: '*',
    allowMethods: 'GET, PUT, POST, DELETE, PATCH'
  };

2全局抛出异常处理

// app/middleware/error_handler.js

module.exports = (option, app) => {
    return async function errorHandler(ctx, next) {
      try {
        await next(); 
        // 404 处理
        if(ctx.status === 404 && !ctx.body){
           ctx.body = { 
               msg:"fail",
               data:'404 错误'
           };
        }
      } catch (err) {
        // 记录一条错误日志
        app.emit('error', err, ctx);

        const status = err.status || 500;
        // 生产环境时 500 错误的详细错误内容不返回给客户端,因为可能包含敏感信息
        const error = status === 500 && app.config.env === 'prod'
          ? 'Internal Server Error'
          : err.message;

        // 从 error 对象上读出各个属性,设置到响应中
        ctx.body = { 
            msg:"fail",
            data:error
        };
        ctx.status = status;
      }
    };
  };

// config/config.default.js

config.middleware = ['errorHandler'];

3封装api返回格式扩展

// app/extend/context.js

module.exports = {
  // 成功提示
  apiSuccess(data = '', msg = 'ok', code = 200) {
    this.body = { msg, data };
    this.status = code;
  },
  // 失败提示
  apiFail(data = '', msg = 'fail', code = 400) {
    this.body = { msg, data };
    this.status = code;
  },
};

4sequelize数据库和迁移配置

数据库配置

安装并配置egg-sequelize插件(它会辅助我们将定义好的 Model 对象加载到 app 和 ctx 上)和mysql2模块:

npm install --save egg-sequelize mysql2

在config/plugin.js中引入 egg-sequelize 插件

exports.sequelize = {
  enable: true,
  package: 'egg-sequelize',
};

在config/config.default.js

config.sequelize = {
    dialect:  'mysql',
    host:  '127.0.0.1',
    username: 'root',
    password:  'root',
    port:  3306,
    database:  'egg-wechat',
    // 中国时区
    timezone:  '+08:00',
    define: {
        // 取消数据表名复数
        freezeTableName: true,
        // 自动写入时间戳 created_at updated_at
        timestamps: true,
        // 字段生成软删除时间戳 deleted_at
        // paranoid: true,
        createdAt: 'created_at',
        updatedAt: 'updated_at',
        // deletedAt: 'deleted_at',
        // 所有驼峰命名格式化
        underscored: true
    }
};

迁移配置

sequelize 提供了sequelize-cli工具来实现Migrations,我们也可以在 egg 项目中引入 sequelize-cli。

npm install --save-dev sequelize-cli

egg 项目中,我们希望将所有数据库 Migrations 相关的内容都放在database目录下,所以我们在项目根目录下新建一个.sequelizerc配置文件:

'use strict';

const path = require('path');

module.exports = {
  config: path.join(__dirname, 'database/config.json'),
  'migrations-path': path.join(__dirname, 'database/migrations'),
  'seeders-path': path.join(__dirname, 'database/seeders'),
  'models-path': path.join(__dirname, 'app/model'),
};

初始化 Migrations 配置文件和目录

npx sequelize init:config
npx sequelize init:migrations
// npx sequelize init:models

行完后会生成database/config.json文件和database/migrations目录,我们修改一下database/config.json中的内容,将其改成我们项目中使用的数据库配置:

{
  "development": {
    "username": "root",
    "password": null,
    "database": "eggapi",
    "host": "127.0.0.1",
    "dialect": "mysql",
    "timezone": "+08:00"
  }
}

创建数据库

npx sequelize db:create
# 升级数据库
npx sequelize db:migrate
# 如果有问题需要回滚,可以通过 `db:migrate:undo` 回退一个变更
# npx sequelize db:migrate:undo
# 可以通过 `db:migrate:undo:all` 回退到初始状态
# npx sequelize db:migrate:undo:all

模型关联

User.associate = function(models) {
   // 关联用户资料 一对一
   User.hasOne(app.model.Userinfo);
   // 反向一对一关联
   // Userinfo.belongsTo(app.model.User);
   // 一对多关联
   User.hasMany(app.model.Post);
   // 反向一对多关联
   // Post.belongsTo(app.model.User);
   // 多对多
   // User.belongsToMany(Project, { as: 'Tasks', through: 'worker_tasks', foreignKey: 'userId' })
   // 反向多对多
   // Project.belongsToMany(User, { as: 'Workers', through: 'worker_tasks', foreignKey: 'projectId' })
}

5用户表设计和迁移

数据表设计和迁移

创建数据迁移表

npx sequelize migration:generate --name=user

1.执行完命令后,会在database / migrations / 目录下生成数据表迁移文件,然后定义

'use strict';

module.exports = {
  up: async (queryInterface, Sequelize) => {
    const { INTEGER, STRING, DATE, ENUM } = Sequelize;
    // 创建表
    await queryInterface.createTable('user', {
      id: {
        type: INTEGER(20).UNSIGNED,
        primaryKey: true,
        autoIncrement: true
      },
      username: {
        type: STRING(30),
        allowNull: false,
        defaultValue: '',
        comment: '用户名称',
        unique: true
      },
      nickname: {
        type: STRING(30),
        allowNull: false,
        defaultValue: '',
        comment: '昵称',
      },
      email: {
        type: STRING(160),
        comment: '用户邮箱',
        unique: true
      },
      password: {
        type: STRING(200),
        allowNull: false,
        defaultValue: ''
      },
      avatar: {
        type: STRING(200),
        allowNull: true,
        defaultValue: ''
      },
      phone: {
        type: STRING(20),
        comment: '用户手机',
        unique: true
      },
      sex: {
        type: ENUM,
        values: ['男', '女', '保密'],
        allowNull: true,
        defaultValue: '男',
        comment: '用户性别'
      },
      status: {
        type: INTEGER(1),
        allowNull: false,
        defaultValue: 1,
        comment: '状态'
      },
      sign: {
        type: STRING(200),
        allowNull: true,
        defaultValue: '',
        comment: '个性签名'
      },
      area: {
        type: STRING(200),
        allowNull: true,
        defaultValue: '',
        comment: '地区'
      },
      created_at: DATE,
      updated_at: DATE
    });
  },

  down: async queryInterface => {
    await queryInterface.dropTable('user');
  }
};

执行 migrate 进行数据库变更

npx sequelize db:migrate

6注册功能实现

新建user.js控制器

// app/controller/user.js
'use strict';

const Controller = require('egg').Controller;

class UserController extends Controller{
    // 注册
    async reg(){
        let {ctx,app} = this;
       // 参数验证
       let {username,password,repassword} = this.ctx.request.body;
       // 验证用户是否已存在
       if(await app.model.User.findOne({
           where:{
               username
           }
       })){
           ctx.throw(400,'用户名已存在');
       }
       // 创建用户
       await app.model.User.create({
           username,
           password
       })
       if(!user){
           ctx.throw(400,'创建用户失败');
       }
       ctx.apiSuccess(user);
    //   this.ctx.body ='注册';   
    }
}


module.exports = UserController;

新建user.js数据迁移文件

// app/model/user.js
'use strict';
module.exports = app => {
    const { STRING, INTEGER, DATE, ENUM, TEXT } = app.Sequelize;
    // 配置(重要:一定要配置详细,一定要!!!)
    const User = app.model.define('user', {
        id: {
            type: INTEGER(20).UNSIGNED,
            primaryKey: true,
            autoIncrement: true
        },
        username: {
            type: STRING(30),
            allowNull: false,
            defaultValue: '',
            comment: '用户名称',
            unique: true
        },
        nickname: {
            type: STRING(30),
            allowNull: false,
            defaultValue: '',
            comment: '昵称',
        },
        email: {
            type: STRING(160),
            comment: '用户邮箱',
            unique: true
        },
        password: {
            type: STRING(200),
            allowNull: false,
            defaultValue: ''
        },
        avatar: {
            type: STRING(200),
            allowNull: true,
            defaultValue: ''
        },
        phone: {
            type: STRING(20),
            comment: '用户手机',
            unique: true
        },
        sex: {
            type: ENUM,
            values: ['男', '女', '保密'],
            allowNull: true,
            defaultValue: '男',
            comment: '用户性别'
        },
        status: {
            type: INTEGER(1),
            allowNull: false,
            defaultValue: 1,
            comment: '状态'
        },
        sign: {
            type: STRING(200),
            allowNull: true,
            defaultValue: '',
            comment: '个性签名'
        },
        area: {
            type: STRING(200),
            allowNull: true,
            defaultValue: '',
            comment: '地区'
        },
        created_at: DATE,
        updated_at: DATE
    });
    return User;
};

注册路由

   // 用户注册
  router.post('/reg',controller.user.reg);

下图是我测试的截图

7参数验证功能实现(一)

参数验证

插件地址:
https://www.npmjs.com/package/egg-valparams

安装

npm i egg-valparams --save

配置

// config/plugin.js
valparams : {
  enable : true,
  package: 'egg-valparams'
},
// config/config.default.js
config.valparams = {
    locale    : 'zh-cn',
    throwError: true
};

在控制器里使用

class XXXController extends app.Controller {
  // ...
  async XXX() {
    const {ctx} = this;
    ctx.validate({
      system  : {type: 'string', required: false, defValue: 'account', desc: '系统名称'},
      token   : {type: 'string', required: true, desc: 'token 验证'},
      redirect: {type: 'string', required: false, desc: '登录跳转'}
    });
    // if (config.throwError === false)
    if(ctx.paramErrors) {
      // get error infos from `ctx.paramErrors`;
    }
    let params = ctx.params;
    let {query, body} = ctx.request;
    // ctx.params        = validater.ret.params;
    // ctx.request.query = validater.ret.query;
    // ctx.request.body  = validater.ret.body;
    // ...
    ctx.body = query;
  }
  // ...
}
// app/controller/user.js
'use strict';

const Controller = require('egg').Controller;

class UserController extends Controller{
    // 注册
    async reg(){
        let {ctx,app} = this;
       // 参数验证
       ctx.validate({
          username:{type: 'string', required: true,range:{min:10,max:20},desc: '用户名'},
          password:{type: 'string', required: true, desc: '密码'},
          repassword:{type: 'string', required: true, desc: '确认密码'}
        },{
            equals:[
                ['password','repassword']
            ]
        });
       let {username,password,repassword} = this.ctx.request.body;
       // 验证用户是否已存在
       if(await app.model.User.findOne({
           where:{
               username
           }
       })){
           ctx.throw(400,'用户名已存在');
       }
       // 创建用户
       await app.model.User.create({
           username,
           password
       }以上是关于uni-app 25后端api开发和前后端交互(1-50)的主要内容,如果未能解决你的问题,请参考以下文章

前端端口是怎么交互后端

微信小程序前后端分离怎么实现

前后端分离方案以及技术选型

uniapp怎么和后端交互

前后端分离后API交互如何保证数据安全性

前后端API交互如何保证数据安全性?(转)