zoukankan      html  css  js  c++  java
  • node+koa中转层开发实践总结

    node中转层的意义:

      1.能解决前后端代码部署在不同服务器下时的跨域问题。(实现)

      2.合并请求,业务逻辑处理。(实现)

      3.单页应用的首屏服务端渲染。(暂未实现)

    环境准备:

      node: ^8.11.2

      koa: ^2.6.1

      koa-router: ^7.4.0

      koa-bodyparser: ^4.2.1

    在项目目录下新建server目录,新建app.js

    const Koa = require('koa');
    const bodyParser = require('koa-bodyparser');
    const apiControler = require('./apiControler');
    
    let app = new Koa();
    global.hostname = "172.16.16.113";
    global.port = 8070;
    
    app.use(async (ctx, next) => {
      await next();
      console.log(`Process ${ctx.request.method} ${ctx.request.url}...`);
    });
    
    //bodyParser必须在router之前注册到app上
    app.use(bodyParser());
    
    //使用路由处理中间件
    app.use(apiControler());
    
    app.listen(8899);
    

    在server目录下新建业务接口目录,本例目录名为apiControlers,拿登录模块为例,新建一个login.js,里面包含登录模块所需要的所有接口。(获取验证码、登录、获取菜单权限)

    login.js

    const http = require('http');
    const hostname = global.hostname;
    const port = global.port;
    let tokenStr = "";
    
    /*获取图形验证码*/
    let getAuthCoedFn = async (ctx, next) => {
      let data = await asyncGetAuthCode();
      ctx.set("Content-Type", "application/json");
      ctx.body = JSON.parse(data);
      await next();
    };
    function asyncGetAuthCode() {
      return new Promise((resolve, reject)=> {
        let authCodedData = "";
        let req = http.request({
          path: '/api/backstage/authCode',
          port: port,
          method: 'GET',
          hostname: hostname
        },(res)=> {
          res.on('data', (chunk)=> {
            authCodedData += chunk
          });
          res.on('end', ()=> {
            authCodedData = JSON.stringify(authCodedData)
            resolve(authCodedData)
          })
        });
        req.on("error", (e)=> {
          console.log("api:/backstage/authCode error")
          reject(e.message)
        });
        req.end();
      })
    }
    
    /*登录*/
    let loginFn = async (ctx, next) => {
      let param = ctx.request.body;
      let authcodekey = ctx.request.header.authcodekey;
      let postData = {
        userName: param.userName,
        authCode: param.authCode,
        password: param.password
      };
      let loginData = await asyncPostLogin(authcodekey, JSON.stringify(postData));
      ctx.set("Content-Type", "application/json");
      ctx.set("Connection", "keep-alive");
      ctx.body = JSON.parse(loginData);
      next()
    };
    function asyncPostLogin(authcodekey, postData) {
      return new Promise((resolve, reject)=> {
        let loginData = "";
        let req = http.request({
          path: '/api/backstage/login',
          port: port,
          method: 'POST',
          hostname: hostname,
          headers: {
            'Content-Type': 'application/json',
            'authCodeKey': authcodekey
          }
        },(res)=> {
          res.on('data', (chunk)=> {
            loginData += chunk
          }).on('end', ()=> {
            loginData = JSON.stringify(loginData);
            tokenStr = res.headers['set-cookie'];
            resolve(loginData)
          })
        });
        req.on('error', (e)=> {
          console.log("api:/backstage/login error");
          reject(e.message)
        });
        req.write(postData);
        req.end();
      })
    }
    
    /*获取菜单及权限列表*/
    let getPowerListFn = async (ctx, next) => {
      let menuList = await asyncGetPowerList();
      ctx.body = JSON.parse(menuList);
      next()
    };
    function asyncGetPowerList() {
      return new Promise((resolve, reject)=> {
        let listData = "";
        let req = http.request({
          path: '/api/backstage/getPowerList',
          method: 'get',
          port: port,
          hostname: hostname,
          headers: {
            'Cookie': tokenStr.toString()
          }
        },(res)=> {
          res.on('data', (chunk)=> {
            listData += chunk;
          }).on('end', ()=> {
            listData = JSON.stringify(listData);
            resolve(listData)
          })
        });
        req.on("error", (e)=> {
          console.log("api: /backstage/getPowerList error");
          reject(e.message)
        });
        req.end()
      })
    }
    
    
    module.exports = {
      'GET/api/backstage/authCode': getAuthCoedFn,
      'POST/api/backstage/login': loginFn,
      'GET/api/backstage/getPowerList': getPowerListFn
    }
    

    以接口功能声明一个函数,在此函数中通过node的http模块发送请求。需要注意的是http.request请求获取响应头cookie的方式是tokenStr = res.headers['set-cookie']

    每一个业务功能js最后暴露出内部所有以接口请求方式+接口地址为key,以对应功能函数为value的对象。

    在server目录下新建一个apiControler.js中间件(有返回值的函数)。此中间件的功能一是读取apiControlers目录下的所有业务js,并引入;二是设置接口请求方式与执行函数的映射关系。

    最后暴露出一个函数返回所有请求接口路径的集合。

    apiControler.js

    const fs = require("fs");
    
    function readApiFiles(router, dir = '/apiControlers') {
      fs.readdirSync(__dirname + dir).filter((f)=> {
        return f.endsWith('.js')
      }).forEach(f => {
        console.log(`process controller: ${f}...`);
        let mapping = require(__dirname + dir + '/' + f);
        addMapping(router, mapping)
      });
    }
    
    function addMapping(router, mapping) {
      for(let url in mapping) {
        if(url.startsWith('GET')) {
          let path = url.substring(3);
          router.get(path, mapping[url]);
        }else if(url.startsWith('POST')) {
          let path = url.substring(4);
          router.post(path, mapping[url]);
        }else{
          router.get(url, mapping[url]);
          console.log(`无效的URL: ${url}`);
        }
      }
    }
    
    module.exports = function (dir) {
      let controllers_dir = dir || '/apiControlers';
      let router = require('koa-router')();
      readApiFiles(router, controllers_dir);
      return router.routes();
    };
    

    最后回到app.js,引入apiControler.js中间件并注册到app上。需要注意的是bodyParser中间件必须在router之前注册到app上。

    后续

      此例目前只能用作接口转发、合并请求和解决跨域问题,终极目标是能解决SPA(单页应用的)首屏服务端渲染问题。

      持续折腾中...

  • 相关阅读:
    Oracle之数据库的增删改查和格式的修改
    Oracle之表的相关操作
    Oracle之现有表上建新表、操作符、字符函数
    Oracle之用户和表空间
    相关Linux命令
    克隆环境
    机器学习笔记(四)神经网络的基本概念
    机器学习作业(二)逻辑回归——Python(numpy)实现
    机器学习作业(二)逻辑回归——Matlab实现
    机器学习笔记(三)逻辑回归
  • 原文地址:https://www.cnblogs.com/zifayin/p/9963755.html
Copyright © 2011-2022 走看看