美文网首页程序员
基于Koa和Mysql的Web Server框架

基于Koa和Mysql的Web Server框架

作者: 知小酌 | 来源:发表于2017-09-17 03:08 被阅读382次

    最近在给一个自定义的项目写接口,第一次使用node.js实现,翻了几天的书和资料,本来计划使用express + mongodb实现的,后来发现了Koa,good boy,数据库最终选定的还是mysql,老搭子嘛,搭建了一个基于Koa + Mysql框架:

    Koa

    koa 是由 Express 原班人马打造的,致力于成为一个更小、更富有表现力、更健壮的 Web 框架。使用 koa 编写 web 应用,通过组合不同的 generator,可以免除重复繁琐的回调函数嵌套,并极大地提升错误处理的效率。koa 不在内核方法中绑定任何中间件,它仅仅提供了一个轻量优雅的函数库,使得编写 Web 应用变得得心应手。

    总体框架

    总体框架

    项目主要分为configapp
    config:配置文件
    app:遵循MVC架构,应用文件

    第三方包

    第三方包

    sequelizenode下的ORM框架,很好很强大,下面的实例中会进行展示。

    主要配置

    Server.js

    
    /**
     * Created by vslimit on 2017/9/8.
     */
    'use strict';
    require('dotenv').config();
    const Koa =require('koa');
    const app = new Koa();
    const fs = require('fs');
    const join = require('path').join;
    const bodyParser = require('koa-bodyparser');
    const model = join(__dirname, 'app/model');
    var Router = require('koa-router');
    var router = new Router();
    const rest = require('./config/rest');
    
    const config = require('./config');
    
    const port = process.env.PORT || 3000;
    
    module.exports = app;
    app.use(bodyParser());
    // app.use(async ctx => {
    //     ctx.body = ctx.request.body;
    // });
    app.use(rest.restify());
    app.use(router.routes()).use(router.allowedMethods());
    
    fs.readdirSync(model)
        .filter(file => ~file.search(/^[^\.].*\.js$/))
        .forEach(file => require(join(model, file)));
    
    
    // let files = fs.readdirSync(model);
    
    
    require('./config/routes')(router);
    
    listen();
    
    module.exports = model;
    
    function listen() {
        if (router.get('env') === 'test') return;
        app.listen(port);
        console.log('Express app started on port ' + port);
    }
    
    
    

    开发实例

    我们应用此框架开发一个功能注册、登录、加载功能的Restful接口,先看下model

    User

    /**
     * Created by vslimit on 2017/9/10.
     */
    const db = require('../util/db');
    const crypto = require('crypto');
    const uuid = require('node-uuid');
    
    const User = db.defineModel('users', {
        name: {
            type: db.STRING(),
            allowNull: true
        },
        email: {
            type: db.STRING(),
            unique: true,
            allowNull: true
        },
        password: db.VIRTUAL(),
        mobile: {
            type: db.STRING(),
            unique: true
        },
        provider: db.STRING(),
        hashed_password: db.STRING(),
        salt: db.STRING(),
        auth_token: {
            type: db.STRING(),
            allowNull: true
        },
        access_token: {
            type: db.STRING(),
            allowNull: true
        }
    
    });
    
    User.beforeValidate(function (user) {
        if (user.isNewRecord) {
            let salt = this.methods.makeSalt();
            user.set('salt', salt);
            user.set('hashed_password', this.methods.encryptPassword(user.password, salt));
        }
    });
    
    User.afterCreate(function (user) {
        console.log(JSON.stringify(user));
        user.access_token = this.methods.makeAccessToken(user.id);
        console.log(user.access_token);
        user.save();
    });
    
    User.methods = {
        authenticate: function (password, salt, hashed_password) {
            return this.encryptPassword(password, salt) === hashed_password;
        },
    
        /**
         * Make salt
         *
         * @return {String}
         * @api public
         */
    
        makeSalt: function () {
            return Math.round((new Date().valueOf() * Math.random())) + '';
        },
    
        /**
         * Encrypt password
         *
         * @param {String} password
         * @return {String}
         * @api public
         */
    
        encryptPassword: function (password, salt) {
            if (!password) return '';
            try {
                return crypto
                    .createHmac('sha1', salt)
                    .update(password)
                    .digest('hex');
            } catch (err) {
                return '';
            }
        },
    
        makeAccessToken: function (id) {
            return crypto
                .createHmac('sha1', id.toString())
                .update(uuid.v4() + Date.now())
                .digest('hex');
        },
    
       load: function (condition) {
            return User.findOne({where: condition});
        },
    
        count: function (condition) {
            return User.count({where: condition});
        },
    };
    
    module.exports = User;
    
    

    然后是controller

    users

    /**
     * Created by vslimit on 2017/9/12.
     */
    'use strict';
    const User = require('../model/User');
    const ApiResult = require('../../config/rest').APIResult;
    
    /**
     *  Create user
     */
    
    exports.create = async(ctx, next) => {
        let mobile = ctx.request.body.mobile;
        let password = ctx.request.body.password;
    
        console.log(mobile);
        console.log(password);
        if (!mobile || !password) {
            ctx.rest(ApiResult("", -102, "手机号或密码不能为空"));
        } else {
            let count = await User.methods.count({mobile: mobile});
            console.log(count);
            if (count > 0) {
                ctx.rest(ApiResult("", -101, "手机号已存在"));
            } else {
                let user = await User.create({
                    mobile: mobile,
                    password: password,
                    provider: 'local'
                });
                ctx.rest(ApiResult(user.access_token));
            }
        }
    
    };
    
    exports.login = async(ctx, next) => {
        let mobile = ctx.request.body.mobile;
        let password = ctx.request.body.password;
        if (!mobile || !password) {
            ctx.rest(ApiResult("", -102, "手机号或密码不能为空"));
        } else {
            let user = await User.methods.load({mobile: mobile});
            if (user) {
                if (User.methods.authenticate(password, user.salt, user.hashed_password)) {
                    ctx.rest(ApiResult({
                        name: user.name,
                        mobile: user.mobile,
                        access_token: user.access_token
                    }));
                } else {
                    ctx.rest(ApiResult("", -105, "用户密码错误"));
                }
            } else {
                ctx.rest(ApiResult("", -103, "用户不存在"));
            }
        }
    };
    
    
    exports.load = async(ctx, next) => {
        var u = await User.findById(ctx.params.id);
        ctx.rest(ApiResult(u));
    };
    
    

    配置route

        app.post('/api/users', users.create);
        app.post('/api/login', users.login);
        app.get('/api/users/:id', users.load);
    
    

    运行

    创建用户 响应 登录响应 加载个人信息

    至此,基于KoaMysql的Web Server框架搭建完成,并实现了注册、登录、加载用户个人信息功能。

    参考资料

    项目中主要参考了

    总体框架
    sequelize文档

    部分代码源自廖雪峰的官网
    官网
    git

    代码

    本文中的所有代码已经提交到git上了,大家如果喜欢就去git下star下吧。

    Koa-Server的代码详见:[https://github.com/vslimit/koa-server.git)

    相关文章

      网友评论

        本文标题:基于Koa和Mysql的Web Server框架

        本文链接:https://www.haomeiwen.com/subject/nxhpsxtx.html