koa使用和API实现

前言

记录一个小项目用 koa 实现前后端的过程

项目地址: https://github.com/MuYi086/koaDemo

工具

开发过程中用到的工具包括但不限于: vscode, mysqlWorkbench, phpStudy, vue, koa, mysql

后端开发过程

  1. 搭建 koa 项目

    # 全局安装koa
    npm i koa -g
    # 全局安装koa2项目生成器
    npm i koa-generator -g
    # 创建项目
    koa2 koaDemo
    # 安装依赖
    cd ./koaDemo && npm i
  2. 丰富项目骨架

    # 安装sequelize, mysql, mysql2
    npm i sequelize mysql mysql2 --save
    # 解决跨域
    npm i koa-cors --save
    # app.js加入koa-cors的引用
    const cors = require('koa-cors')
    app.use(cors())
  3. 根目录创建 config 目录, config 目录中创建 db.js

    const Sequelize = require('sequelize')
    const user = {dbName: 'koa', dbUserName: 'koa', password: 'koa'}
    const sequelize = new Sequelize(user.dbName, user.dbUserName, user.password, {
        host: 'localhost',
        dialect: 'mysql',
        operatorsAliases: false,
        dialectOptions: {
            // 字符集
            charset: 'utf8mb4',
            collate: 'utf8mb4_unicode_ci',
            supportBigNumbers: true,
            bigNumberStrings: true
        },
        pool: {
            max: 5,
            min: 0,
            acquire: 30000,
            idle: 10000
        },
        timezone: '+8:00' // 东八区
    });
    module.exports = {sequelize}
  4. 创建 schema 目录,用于放置数据表模型实例,创建 forward.js

    const moment = require('moment')
    module.exports = function(sequelize, DataTypes) {
        return sequelize.define('forward', {
            name: {
                type: DataTypes.STRING,
                allowNull: false,
                field:'name'
            },
            id: {
                type: DataTypes.INTEGER,
                allowNull: false,
                field: 'id'
            },
            price: {
                type: DataTypes.INTEGER,
                allowNull: false,
                field: 'price'
            },
            deposit: {
                type: DataTypes.INTEGER,
                allowNull: false,
                field: 'deposit'
            },
            uuid: {
                type: DataTypes.INTEGER,
                primaryKey: true,
                allowNull: true,
                autoIncrement: true
            }
        }, {
            freezeTableName: true
        })
    }
  5. 创建 modules 目录, 用于放置实体模型, 创建 forward.js

    // 引入mysql配置文件
    const db = require('../config/db')
    const Sequelize = db.sequelize
    // 引入数据表模型
    const ForWard = Sequelize.import('../schema/forward')
    ForWard.sync({force: false}) // 自动创建表
    class ForWardModel {
        /**
        * 创建合约模型
        * @param data
        * @returns {Promise<*>}
        */
        static async createForWard(data) {
            return await ForWard.create({
                name: data.name,
                id: data.id,
                price: data.price,
                deposit: data.deposit
            })
        }
    
        /**
        * 查询合约列表
        * @param id 文章id
        * @returns {Promise<Model}
        */
        static async getForWardList(id) {
            return await ForWard.findOne({
                where: {
                    id
                }
            })
        }
    }
    
    module.exports = ForWardModel
  6. 创建 controller 目录,用于放置控制器, 创建 forward.js

    const ForWardModel = require('../modules/forward')
    class forWardController {
        /**
        * 创建合约
        * @param ctx
        * @returns {Promise.<void>}
        */
        static async create(ctx) {
            // 接受客户端
            let req = ctx.request.body
            if(req.name && req.id && req.price && req.deposit) {
                try {
                    // 创建合约模型
                    const ret = await ForWardModel.createForWard(req)
                    // 使用刚刚创建的id查询合约列表,且返回合约信息
                    const data = await ForWardModel.getForWardList(ret.id)
    
                    ctx.response.status = 200
                    ctx.body = {
                        code: 200, 
                        msg: '创建合约成功',
                        data
                    }
                } catch(err) {
                    ctx.response.status = 412
                    ctx.body = {
                        code: 412,
                        msg: '创建合约失败',
                        data: err
                    }
                }
            } else {
                ctx.response.status = 416
                ctx.body = {
                    code: 200,
                    msg: '参数不全'
                }
            }
        }
    
        /**
        * 获取合约详情
        * @param ctx
        * @returns {Promise.<void>}
        */
        static async detail(ctx) {
            let id = ctx.params.id
            if (id) {
                try {
                    // 查询合约详情模型
                    let data = await ForWardModel.getForWardList(id)
                    ctx.response.status = 200
                    ctx.body = {
                        code: 200,
                        msg: '查询成功',
                        data
                    }
                } catch (err) {
                    ctx.response.status = 412
                    ctx.body = {
                        code: 412,
                        msg: '查询失败',
                        data: err
                    }
                }
            } else {
                ctx.response.status = 416
                ctx.body = {
                    code: 416,
                    msg: '合约id必须要传'
                }
            }
        }
    }
    
    module.exports = forWardController
  7. routes 目录下 index.js 增加路由

    const ForWardController = require('../controllers/forward')
    
    // 创建合约
    router.post('/forward/create', ForWardController.create)
    // 获取合约详情
    router.get('/forward/:id', ForWardController.detail)
  8. 启动服务

    npm start

前端开发过程

  1. 利用 vue-cli 新建一个项目,安装依赖

    vue init webpack koafront
    cd ./koafront && npm i
  2. 利用 proxyTable 设置跨域

    proxyTable: {
        '/api': {
            target: "http://localhost:3000",
            changeOrigin: true,
            pathRewrite: {
            '^/api': ""
            }
        }
    },
  3. 使用 axios 请求

    axios.get('api/forward/101').then(function (res) {
        console.log(res)
    }).catch(function (error) {
        console.log(error)
    })
  4. 使用 scss 预处理器

    # 安装node-sass、sass-loader、style-loader
    # 注意这里sass-loader安装是尝试过的可用版本,最新版本会抛错
    npm i sass-loader@7.3.1 --save-dev
    npm i node-sass style-loader --save-dev
  5. 配置 build 目录下的 webpack.base.conf.js 文件

    // 在rules规则加上如下:
    {
        test: /\.scss$ /,
        loaders: ['style', 'css', 'sass']
    },
  6. 安装 sass-resource-loader 来全局引入

    npm i sass-resources-loader --save-dev
  7. 修改 build 中的 utils.js 配置

    // 将
    scss: generateLoaders('sass'),
    // 替换为
    scss: generateLoaders('sass').concat(
      {
        loader: 'sass-resources-loader',
        options: {
          // scss全局文件路径
          resources: path.resolve(__dirname, '../src/assets/css/site.scss')
        }
      }
    ),

思考

  1. 使用 nginx 代理实现跨域

参考

Last updated