浅谈KOA2 Restful方式路由初探


Posted in Javascript onMarch 14, 2019

前言

最近考虑将服务器资源整合一下,作为多端调用的API

看到Restful标准和ORM眼前一亮,但是找了不少版本路由写的都比较麻烦,于是自己折腾了半天

API库结构

考虑到全部对象置于顶层将会造成对象名越来长,同时不便于维护,故采取部分的分层结构

如workflow模块内的prototypes,instances等等,分层的深度定义为层级

可访问的对象集合(collection)的属性满足Restful设计

-- workflow(category)
  -- prototypes(collection)
    -- [method] ...
    -- [method] ... 
  -- instances(collection)
 -- users(collection)
   --[method] List     #get :object/
   --[method] Instance   #get :object/:id
 -- ...
 -- ...

RESTFUL API 接口

将Restful API接口进行标准化命名

.get('/', ctx=>{ctx.error('路径匹配失败')})        
.get('/:object', RestfulAPIMethods.List)
.get('/:object/:id', RestfulAPIMethods.Get)
.post('/:object', RestfulAPIMethods.Post)
.put('/:object/:id', RestfulAPIMethods.Replace)
.patch('/:object/:id', RestfulAPIMethods.Patch)
.delete('/:object/:id', RestfulAPIMethods.Delete)
.get('/:object/:id/:related', RestfulAPIMethods.Related)
.post('/:object/:id/:related', RestfulAPIMethods.AddRelated)
.delete('/:object/:id/:related/:relatedId', RestfulAPIMethods.DelRelated)

API对象

这个文件是来自微信小程序demo,觉得很方便就拿来用了,放于需要引用的根目录,引用后直接获得文件目录结构API对象

const _ = require('lodash')
const fs = require('fs')
const path = require('path')

/**
 * 映射 d 文件夹下的文件为模块
 */
const mapDir = d => {
  const tree = {}

  // 获得当前文件夹下的所有的文件夹和文件
  const [dirs, files] = _(fs.readdirSync(d)).partition(p => fs.statSync(path.join(d, p)).isDirectory())

  // 映射文件夹
  dirs.forEach(dir => {
    tree[dir] = mapDir(path.join(d, dir))
  })

  // 映射文件
  files.forEach(file => {
    if (path.extname(file) === '.js') {
      tree[path.basename(file, '.js')] = require(path.join(d, file))
      tree[path.basename(file, '.js')].isCollection = true
    }
  })

  return tree
}



// 默认导出当前文件夹下的映射
module.exports = mapDir(path.join(__dirname))

koa-router分层路由的实现

创建多层路由及其传递关系

执行顺序为

 1 -- 路径匹配
    -- 匹配到‘/'结束
    -- 匹配到对应的RestfulAPI执行并结束
    -- 继续
 2 -- 传递中间件 Nest
 3 -- 下一级路由
 4 -- 循环 to 1

const DefinedRouterDepth = 2
let routers = []
for (let i = 0; i < DefinedRouterDepth; i++) {
  let route = require('koa-router')()
  if (i == DefinedRouterDepth - 1) {
    // 嵌套路由中间件
    route.use(async (ctx, next) => {
      // 根据版本号选择库
      let apiVersion = ctx.headers['api-version']
      ctx.debug(`------- (API版本 [${apiVersion}]) --=-------`)
       if (!apiVersion) {
        ctx.error('版本号未标记')
        return
      }
      let APIRoot = null
      try {
        APIRoot = require(`../restful/${apiVersion}`)
      } catch (e) {
        ctx.error ('API不存在,请检查Header中的版本号')
        return
      }
      ctx.debug(APIRoot)
      ctx.apiRoot = APIRoot
      ctx.debug('---------------------------------------------')
      // for(let i=0;i<)
      await next()
    })
  }
  route
    .get('/', ctx=>{ctx.error('路径匹配失败')})
    .get('/:object', RestfulAPIMethods.List)
    .get('/:object/:id', RestfulAPIMethods.Get)
    .post('/:object', RestfulAPIMethods.Post)
    .put('/:object/:id', RestfulAPIMethods.Replace)
    .patch('/:object/:id', RestfulAPIMethods.Patch)
    .delete('/:object/:id', RestfulAPIMethods.Delete)
    .get('/:object/:id/:related', RestfulAPIMethods.Related)
    .post('/:object/:id/:related', RestfulAPIMethods.AddRelated)
    .delete('/:object/:id/:related/:relatedId', RestfulAPIMethods.DelRelated)


  if (i != 0) {
    route.use('/:object', Nest, routers[i - 1].routes())
  }
  routers.push(route)
}
let = router = routers[routers.length - 1]

Nest中间件

将ctx.apiObject设置为当前层的API对象

const Nest= async (ctx, next) => {
  let object = ctx.params.object
  let apiObject = ctx.apiObject || ctx.apiRoot
  if(!apiObject){
    ctx.error('API装载异常')
    return
  }

  if (apiObject[object]) {
    ctx.debug(`ctx.apiObject=>ctx.apiObject[object]`)
    ctx.debug(apiObject[object])
    ctx.debug(`------------------------------------`)
    ctx.apiObject = apiObject[object]
  } else {
    ctx.error(`API接口${object}不存在`)
    return
  }


  await next()
}

RestfulAPIMethods

let RestfulAPIMethods = {}
let Methods = ['List', 'Get', 'Post', 'Replace', 'Patch', 'Delete', 'Related', 'AddRelated', 'DelRelated']
for (let i = 0; i < Methods.length; i++) {
  let v = Methods[i]
  RestfulAPIMethods[v] = async function (ctx, next) {
    
    let apiObject = ctx.apiObject || ctx.apiRoot
    if (!apiObject) {
      ctx.error ('API装载异常')
      return
    }
    let object = ctx.params.object
    if (apiObject[object] && apiObject[object].isCollection) {
      ctx.debug(` --- Restful API [${v}] 调用--- `)
      if (typeof apiObject[object][v] == 'function') {
        ctx.state.data = await apiObject[object][v](ctx)
        ctx.debug('路由结束')
        return
        //ctx.debug(ctx.state.data)
      } else {
        ctx.error(`对象${object}不存在操作${v}`)
        return
      }
    }
    ctx.debug(` --- 当前对象${object}并不是可访问对象 --- `)
    await next()
  }
}

需要注意的点

1、koa-router的调用顺序
2、涉及到async注意next()需要加await

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
javascript 建设银行登陆键盘
Jun 10 Javascript
jquery tab插件制作实现代码
Jun 22 Javascript
juqery 学习之三 选择器 简单 内容
Nov 25 Javascript
原生Js页面滚动延迟加载图片实现原理及过程
Jun 24 Javascript
JQuery为页面Dom元素绑定事件及解除绑定方法
Apr 23 Javascript
jQuery中unwrap()方法用法实例
Jan 16 Javascript
微信小程序 Canvas增强组件实例详解及源码分享
Jan 04 Javascript
bootstrap table表格客户端分页实例
Aug 07 Javascript
用React实现一个完整的TodoList的示例代码
Oct 30 Javascript
详解vue2.0+vue-video-player实现hls播放全过程
Mar 02 Javascript
vue.js学习笔记之v-bind和v-on解析
May 03 Javascript
JavaScript架构搭建前端监控如何采集异常数据
Jun 25 Javascript
详解微信小程序scroll-view横向滚动的实践踩坑及隐藏其滚动条的实现
Mar 14 #Javascript
详解React项目中碰到的IE问题
Mar 14 #Javascript
Node.js + express实现上传大文件的方法分析【图片、文本文件】
Mar 14 #Javascript
React+Antd+Redux实现待办事件的方法
Mar 14 #Javascript
Node.js + express基本用法教程
Mar 14 #Javascript
Vue渲染过程浅析
Mar 14 #Javascript
详解关于JSON.parse()和JSON.stringify()的性能小测试
Mar 14 #Javascript
You might like
为PHP5.4开启Zend OPCode缓存
2014/12/26 PHP
PHP常见漏洞攻击分析
2016/02/21 PHP
JSON传递bool类型数据的处理方式介绍
2013/09/18 Javascript
JS动态修改iframe高度和宽度的方法
2015/04/01 Javascript
javascript弹性运动效果简单实现方法
2016/01/08 Javascript
js自调用匿名函数的三种写法(推荐)
2016/08/19 Javascript
JQuery动态添加Select的Option元素实现方法
2016/08/29 Javascript
vue2.0开发实践总结之疑难篇
2016/12/07 Javascript
js 实现省市区三级联动菜单效果
2017/02/20 Javascript
微信小程序canvas写字板效果及实例
2017/06/15 Javascript
Three.js利用顶点绘制立方体的方法详解
2017/09/27 Javascript
基于element-ui的rules中正则表达式
2018/09/04 Javascript
vue权限问题的完美解决方案
2019/05/08 Javascript
jQuery 选择器用法实例分析【prev + next】
2020/05/22 jQuery
python计算对角线有理函数插值的方法
2015/05/07 Python
用tensorflow搭建CNN的方法
2018/03/05 Python
python-opencv颜色提取分割方法
2018/12/08 Python
在python环境下运用kafka对数据进行实时传输的方法
2018/12/27 Python
Python微医挂号网医生数据抓取
2019/01/24 Python
Django框架登录加上验证码校验实现验证功能示例
2019/05/23 Python
Python 循环终止语句的三种方法小结
2019/06/24 Python
pandas-resample按时间聚合实例
2019/12/27 Python
利用Pytorch实现简单的线性回归算法
2020/01/15 Python
Python post请求实现代码实例
2020/02/28 Python
Django model.py表单设置默认值允许为空的操作
2020/05/19 Python
Scrapy+Selenium自动获取cookie爬取网易云音乐个人喜爱歌单
2021/02/01 Python
css3高级选择器使用方法
2013/12/02 HTML / CSS
编码转换,怎样实现将GB2312编码的字符串转换为ISO-8859-1编码的字符串
2014/01/07 面试题
公司财务工作总结的自我评价
2013/11/23 职场文书
本科生求职信
2014/06/17 职场文书
中学生民族团结演讲稿
2014/08/27 职场文书
2015年上半年物业工作总结
2015/03/30 职场文书
催款律师函范文
2015/05/27 职场文书
深度好文:50条没人告诉你的人生经验,句句精辟
2019/08/22 职场文书
Python批量将csv文件转化成xml文件的实例
2021/05/10 Python
在Centos 8.0中安装Redis服务器的教程详解
2022/03/21 Redis