zoukankan      html  css  js  c++  java
  • Koa2+mongoose

    为什么选择Koa
    koa是Express框架同个公司的产品,是开发者在node7.0版本之后使用promise的api把express再次封装了一次,起名KoaKoa=Express+Promise,并且中间件的使用由链型变成了环形【洋葱】

    官网
    网友笔记

    安装

    cnpm i koa --save
    

    最基础使用

    const Koa = require('koa');
    const app = new Koa();
    app.listen(3000);
    

    中间件middleware
    处在 HTTP Request 和 HTTP Response 中间,用来实现某种中间功能的函数,就叫做"中间件",每个中间件默认接受两个参数,第一个参数是 Context 对象,第二个参数是next函数。只要调用next函数,就可以把执行权转交给下一个中间件
    我们需要的中间件有

    • koa-body 处理post请求
    • koa-router 智能处理路由
    • koa2-cors 跨域
    • mongoose 连接数据库
    • log4js 日记记录插件
    • module-alias 路径引用,避免非常长的相对路径

    其他中间件有,因为使用前后端分离所以用不到

    • koa-staic ,静态文件访问
    • koa-view ,服务器渲染的插件
    • koa-session ,koa内置了cookie方法,只需要下载session

    我的目录建议

    • 一个入口文件叫app.js或者叫server.js
    • 一个config.js放置一些全局的配置
    • 一个api文件夹放我的路由
    • 一个request文件夹放我的请求
    • 一个router文件夹放路由配置入口
    • 一个utils文件夹放一些时间处理,uuid的插件js
    • 一个mongoose文件夹放数据库的连接入口,里面再建一个model文件夹
    • 一个middleware文件夹放自己的中间件

    上代码
    需要先把上面的中间件安装了

    // app.js 入口文件
    
    const Koa = require('koa')
    const koaBody = require('koa-body');
    const cors = require('koa2-cors')
    const config = require('./src/config')
    const router = require('./src/router')
    //启动的时候连接一下mongodb,不需要use
    const mongoose = require('./src/mongoose')  
    // 自定义中间件
    const whiteList = require('./src/middleware/whiteList')
    
    const app = new Koa()
    app.use(whiteList());  //白名单放第一位
    app.use(koaBody({
        formLimit:10000 * 1024 * 1024,   //JSON 数据体的大小限制,默认56k
        textLimit:10000 * 1024 * 1024,   //限制表单请求体的大小,默认56k
        jsonLimit:10000 * 1024 * 1024,   //限制 text body 的大小,默认56k
        multipart: true,
            formidable: {
                maxFileSize: 2000 * 1024 * 1024    // 设置上传文件大小最大限制,默认2M
            }
    }));
    app.use(xmlParse());
    app.use(cors());  //放到route前面,跨域
    app.use(router.routes());
    app.use(router.allowedMethods());
    
    app.listen(config.port)
    console.log('server start at port:', config.port)
    
    // config.js
    
    module.exports = {
        port: 3000,
        filePath:'E:\nginx-1.16.1\html\uploadFile\',   //开发环境
        // filePath:'/usr/local/nginx/html/uploadFile/',   //正式环境
        fileUrl : "http://localhost/uploadFile/",          //开发环境
        // fileUrl : "http://47.97.201.201/uploadFile/",   //正式环境
        // 白名单
        whiteList:[
            "127.0.0.1:8848",
            "127.0.0.1:8080"
        ]
    }
    
    // router/index.js
    
    const Router = require('koa-router')
    const router = new Router()
    
    router.get('/get', api.get)
    router.post('/post', api.post)
    router.post('/uploadFile', api.uploadFile)
    router.post('/uploadFiles', api.uploadFiles)
    router.post('/uploadBase64', api.uploadBase64)
    
    module.exports = router
    
    // api/index.js
    
    const upload = require('../util/upload')
    
    exports.get  = async (ctx, next) => {
        get方式的取query的值
        let query = ctx.request.query;
        await next();
        ctx.body = query;  //返回值
    }
    exports.post  = async (ctx, next) => {
        //post取body的值
        let body = ctx.request.body;  
        await next();
        ctx.body = body;  //返回值
    }
    exports.uploadFile  = async (ctx, next) => {
        let body = ctx.request.body;
        var res = await upload.uploadFile(ctx)
        await next();
        ctx.body = {file:res};  //返回值
    }
    exports.uploadBase64  = async (ctx, next) => {
        let body = ctx.request.body;
        var res = await upload.uploadBase64(body.file,body.fileName)
        await next();
        ctx.body = {file:res};  //返回值
    }
    
    // util/upload.js
    
    const path = require("path");
    const fs = require("fs");
    const uuid = require('./uuid');  // 自己写一个
    const config = require('../config');
    let Duplex = require('stream').Duplex;
    
    exports.uploadFile = async function(ctx) {
        // 上传单个文件
        const file = ctx.request.files.file; // 获取上传文件
        // 创建可读流
        const reader = fs.createReadStream(file.path);
        let fileId = uuid()
        let fileName = file.name;
        let newName = fileId + "_" + fileName;
        let filePath = config.filePath + `${newName}`;
        // 创建可写流
        const stream = fs.createWriteStream(filePath);
        // 可读流通过管道写入可写流
        reader.pipe(stream);
        return {fileId,fileName,newName,fileUrl:config.fileUrl,url:filePath};
    }
    
    exports.uploadBase64 = async function(file,fileName) {
        // 上传单个base64
        // 创建可读流
        var base64 = file.replace(/^data:.+;base64,/,"");
        var buffer = Buffer.from(base64, 'base64');
        let fileId = uuid()
        let newName = fileId + "_" + fileName;
        let filePath = config.filePath + `${newName}`;
        let reader = new Duplex();
        reader.push(buffer);
        reader.push(null);
        const stream = fs.createWriteStream(filePath);
        // 可读流通过管道写入可写流
        reader.pipe(stream);
        return {fileId,fileName,newName,fileUrl:config.fileUrl,url:filePath};
    }
    
    // mongoose/index.js
    
    var mongoose = require('mongoose');
    mongoose.set('useFindAndModify', false)
    mongoose.connect('mongodb://localhost/mydb',{useNewUrlParser:true,useUnifiedTopology: true},function(err){
        if(err){
            console.log('Connection Error:' + err)
        }else{
            console.log('mongoose Connection success!')
        }
    });
    
    module.exports = mongoose;
    
    // 自定义白名单中间件
    // middleware/whiteList.js
    
    const config = require('../config')
    
    module.exports = () => {
        return async (ctx, next) => {
            var referer = ctx.request.header.referer;
            var origin = ctx.request.header.origin;
            if(referer==undefined||origin==undefined){
                await next()  //可以再网页之外访问
            }else{
                let whiteList = config.whiteList;
                if(whiteList.includes(origin.split("//")[1])){
                    await next()
                }else{
                    ctx.body = "访问地址不在白名单内";
                }
            }
        }
    }
    
    // utils/logger.js 
    
    const log4js = require('log4js'); 
    const path = require('path') 
    // 定义log config 
    log4js.configure({ 
      appenders: { 
         // 定义两个输出源 
         info: { type: 'file', filename: path.resolve('log/info.log') }, 
         error: { type: 'file', filename: path.resolve('log/error.log') } 
      }, 
      categories: { 
         // 为info/warn/debug 类型log调用info输出源 error/fatal 调用error输出源 
         default: { appenders: ['info'], level: 'info' }, 
         info: { appenders: ['info'], level: 'info' }, 
         warn: { appenders: ['info'], level: 'warn' }, 
         debug: { appenders: ['info'], level: 'debug' }, 
         error: { appenders: ['error'], level: 'error' }, 
         fatal: { appenders: ['error'], level: 'fatal' }, 
      } 
    }); 
    // 导出5种类型的 logger 
    module.exports = { 
       debug: (...params) => log4js.getLogger('debug').debug(...params), 
       info: (...params) => log4js.getLogger('info').info(...params), 
       warn: (...params) => log4js.getLogger('warn').warn(...params), 
       error: (...params) => log4js.getLogger('error').error(...params), 
       fatal: (...params) => log4js.getLogger('fatal').fatal(...params), 
    } 
    
    //  使用
    const logger = require('./utils/logger.js')
    //  记录访问,可以自己写一个中间件
    logger.info('请求url:', url , method||'get', JSON.stringify(data))
    

    上面的代码,配置了一个能直接用Koa项目,包括了文件上传的代码,mongodb数据库连接,路由怎么写,还有白名单过滤器,mongoose的使用查看mongoose笔记,下一篇用Koa连接微信服务器

    Egg
    除了这两个框架外,还有一个Egg是阿里封装的,Egg的文档是这么说的,Egg 继承于 Koa,如上述,Koa 是一个非常优秀的框架,然而对于企业级应用来说,它还比较基础,而Egg选择了Koa作为其基础框架,在它的模型基础上,进一步对它进行了一些增强,我看了他的文档使用,应该是把Koa加Java的MVC模式融合再了一起,Egg=Koa+MVC,这个框架更加规范严格企业化,让每个路由都继承框架内部的Controller类和Service 类, 并且把数据库查询存到this里,随时可以调用,最优秀的是他的方法执行是用文件路径指向的,就非常像Java框架里的注解扫描了,代码如下

    // app/router.js
    module.exports = app => {
      app.router.get('/user/:id', app.controller.user.info);
    };
    
    // app/controller/user.js
    const Controller = require('egg').Controller;
    class UserController extends Controller {
      async info() {
        const { ctx } = this;
        const userId = ctx.params.id;
        const userInfo = await ctx.service.user.find(userId);
        ctx.body = userInfo;
      }
    }
    module.exports = UserController;
    
    // app/service/user.js
    const Service = require('egg').Service;
    class UserService extends Service {
      // 默认不需要提供构造函数。
      // constructor(ctx) {
      //   super(ctx); 如果需要在构造函数做一些处理,一定要有这句话,才能保证后面 `this.ctx`的使用。
      //   // 就可以直接通过 this.ctx 获取 ctx 了
      //   // 还可以直接通过 this.app 获取 app 了
      // }
      async find(uid) {
        // 假如 我们拿到用户 id 从数据库获取用户详细信息
        const user = await this.ctx.db.query('select * from user where uid = ?', uid);
    
        // 假定这里还有一些复杂的计算,然后返回需要的信息。
        const picture = await this.getPicture(uid);
    
        return {
          name: user.user_name,
          age: user.age,
          picture,
        };
      }
    
      async getPicture(uid) {
        const result = await this.ctx.curl(`http://photoserver/uid=${uid}`, { dataType: 'json' });
        return result.data;
      }
    }
    module.exports = UserService;
    
    // curl http://127.0.0.1:7001/user/1234
    
  • 相关阅读:
    【修正】gooogleman嵌入式联盟部分图标,并增加gooogleman名片(20101205)
    【程序基础】==和=号的区别
    gooogleman嵌入式开发板联盟准备配发嵌入式视频教程
    【终极版】gooogleman嵌入式开发板联盟图标发布以及使用说明
    关于wince驱动和应用学习的N个问题
    【原创】深刻体会wince 驱动中Sleep函数的作用
    网站策划的经典语录
    repeater中用单选按钮
    一个专业制作网站者的自白
    (原创)文件压缩代码
  • 原文地址:https://www.cnblogs.com/pengdt/p/12072508.html
Copyright © 2011-2022 走看看