经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » JS/JS库/框架 » Node.js » 查看文章
浅谈KOA2 Restful方式路由初探
来源:jb51  时间:2019/3/15 8:33:55  对本文有异议

前言

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

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

API库结构

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

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

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

  1. -- workflow(category)
  2. -- prototypes(collection)
  3. -- [method] ...
  4. -- [method] ...
  5. -- instances(collection)
  6. -- users(collection)
  7. --[method] List #get :object/
  8. --[method] Instance #get :object/:id
  9. -- ...
  10. -- ...

RESTFUL API 接口

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

  1. .get('/', ctx=>{ctx.error('路径匹配失败')})
  2. .get('/:object', RestfulAPIMethods.List)
  3. .get('/:object/:id', RestfulAPIMethods.Get)
  4. .post('/:object', RestfulAPIMethods.Post)
  5. .put('/:object/:id', RestfulAPIMethods.Replace)
  6. .patch('/:object/:id', RestfulAPIMethods.Patch)
  7. .delete('/:object/:id', RestfulAPIMethods.Delete)
  8. .get('/:object/:id/:related', RestfulAPIMethods.Related)
  9. .post('/:object/:id/:related', RestfulAPIMethods.AddRelated)
  10. .delete('/:object/:id/:related/:relatedId', RestfulAPIMethods.DelRelated)

API对象

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

  1. const _ = require('lodash')
  2. const fs = require('fs')
  3. const path = require('path')
  4.  
  5. /**
  6. * 映射 d 文件夹下的文件为模块
  7. */
  8. const mapDir = d => {
  9. const tree = {}
  10.  
  11. // 获得当前文件夹下的所有的文件夹和文件
  12. const [dirs, files] = _(fs.readdirSync(d)).partition(p => fs.statSync(path.join(d, p)).isDirectory())
  13.  
  14. // 映射文件夹
  15. dirs.forEach(dir => {
  16. tree[dir] = mapDir(path.join(d, dir))
  17. })
  18.  
  19. // 映射文件
  20. files.forEach(file => {
  21. if (path.extname(file) === '.js') {
  22. tree[path.basename(file, '.js')] = require(path.join(d, file))
  23. tree[path.basename(file, '.js')].isCollection = true
  24. }
  25. })
  26.  
  27. return tree
  28. }
  29.  
  30.  
  31.  
  32. // 默认导出当前文件夹下的映射
  33. module.exports = mapDir(path.join(__dirname))
  34.  

koa-router分层路由的实现

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

执行顺序为

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

  1. const DefinedRouterDepth = 2
  2. let routers = []
  3. for (let i = 0; i < DefinedRouterDepth; i++) {
  4. let route = require('koa-router')()
  5. if (i == DefinedRouterDepth - 1) {
  6. // 嵌套路由中间件
  7. route.use(async (ctx, next) => {
  8. // 根据版本号选择库
  9. let apiVersion = ctx.headers['api-version']
  10. ctx.debug(`------- (API版本 [${apiVersion}]) --=-------`)
  11. if (!apiVersion) {
  12. ctx.error('版本号未标记')
  13. return
  14. }
  15. let APIRoot = null
  16. try {
  17. APIRoot = require(`../restful/${apiVersion}`)
  18. } catch (e) {
  19. ctx.error ('API不存在,请检查Header中的版本号')
  20. return
  21. }
  22. ctx.debug(APIRoot)
  23. ctx.apiRoot = APIRoot
  24. ctx.debug('---------------------------------------------')
  25. // for(let i=0;i<)
  26. await next()
  27. })
  28. }
  29. route
  30. .get('/', ctx=>{ctx.error('路径匹配失败')})
  31. .get('/:object', RestfulAPIMethods.List)
  32. .get('/:object/:id', RestfulAPIMethods.Get)
  33. .post('/:object', RestfulAPIMethods.Post)
  34. .put('/:object/:id', RestfulAPIMethods.Replace)
  35. .patch('/:object/:id', RestfulAPIMethods.Patch)
  36. .delete('/:object/:id', RestfulAPIMethods.Delete)
  37. .get('/:object/:id/:related', RestfulAPIMethods.Related)
  38. .post('/:object/:id/:related', RestfulAPIMethods.AddRelated)
  39. .delete('/:object/:id/:related/:relatedId', RestfulAPIMethods.DelRelated)
  40.  
  41.  
  42. if (i != 0) {
  43. route.use('/:object', Nest, routers[i - 1].routes())
  44. }
  45. routers.push(route)
  46. }
  47. let = router = routers[routers.length - 1]
  48.  

Nest中间件

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

  1. const Nest= async (ctx, next) => {
  2. let object = ctx.params.object
  3. let apiObject = ctx.apiObject || ctx.apiRoot
  4. if(!apiObject){
  5. ctx.error('API装载异常')
  6. return
  7. }
  8.  
  9. if (apiObject[object]) {
  10. ctx.debug(`ctx.apiObject=>ctx.apiObject[object]`)
  11. ctx.debug(apiObject[object])
  12. ctx.debug(`------------------------------------`)
  13. ctx.apiObject = apiObject[object]
  14. } else {
  15. ctx.error(`API接口${object}不存在`)
  16. return
  17. }
  18.  
  19.  
  20. await next()
  21. }

RestfulAPIMethods

  1. let RestfulAPIMethods = {}
  2. let Methods = ['List', 'Get', 'Post', 'Replace', 'Patch', 'Delete', 'Related', 'AddRelated', 'DelRelated']
  3. for (let i = 0; i < Methods.length; i++) {
  4. let v = Methods[i]
  5. RestfulAPIMethods[v] = async function (ctx, next) {
  6. let apiObject = ctx.apiObject || ctx.apiRoot
  7. if (!apiObject) {
  8. ctx.error ('API装载异常')
  9. return
  10. }
  11. let object = ctx.params.object
  12. if (apiObject[object] && apiObject[object].isCollection) {
  13. ctx.debug(` --- Restful API [${v}] 调用--- `)
  14. if (typeof apiObject[object][v] == 'function') {
  15. ctx.state.data = await apiObject[object][v](ctx)
  16. ctx.debug('路由结束')
  17. return
  18. //ctx.debug(ctx.state.data)
  19. } else {
  20. ctx.error(`对象${object}不存在操作${v}`)
  21. return
  22. }
  23. }
  24. ctx.debug(` --- 当前对象${object}并不是可访问对象 --- `)
  25. await next()
  26. }
  27. }

需要注意的点

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

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

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号