Koa在实际的业务场景中,路由如何做分割?【文末留言送书】

大家好,我是若川。文末留言送书,具体规则文末说明。另外为了鼓励大家多写源码共读笔记,我会在写了5次及以上笔记的作者群里也抽奖送这本书。以后也会有更多福利倾斜。

3ce37dcd64660c068fedf25387bf3e86.png

导读:Koa是一个Node框架,在Node开源社区中,Koa的使用范围非常广,掌握Koa的使用方法,就能轻松应对业界的一些BFF框架。本文介绍Koa在实际的业务场景中,路由如何做分割。

a45c84c43a2d481224b497b263be28d1.png

作者:刘江虹

来源:华章计算机(hzbook_jsj)

在实际的复杂业务场景中,简单的路由堆砌会使得路由文件越来越大,随着后续的项目不断迭代,开发人员的不断更替,如果所有的路由都写在一个文件里,会使得路由模块变得越来越难维护。

那么,Koa的项目要如何去解决路由难维护的问题呢?对于这个问题,由抖音电商前端架构师撰写的《Koa开发:入门、进阶与实战》给出了很好的解决方案,下面让我们结合这本书的内容来详细看一看Koa中路由的使用技巧。

在介绍路由分割以及文件路由之前,我们回忆一下koa-router这个中间件的使用。假如需要两个路由,一个是获取货物信息,一个是获取用户信息,那用koa-router实现的代码应该是这样的:

const Koa = require('koa')const app = new Koa()const Router = require('koa-router')const router = new Router()router.get('/goods/getInfo', async ( ctx ) => {ctx.body = 'this is koa book.'})router.get('/user/getInfo', async ( ctx ) => {ctx.body = 'my name is liujianghong.'})app.use(router.routes())app.listen(4000, () => {console.log('server is running, port is 4000')})

这样的写法相信读者应该已经掌握了,但这样写其实有个弊端,如果在一个实际的项目中,Node.js层的接口可能会很多,所有的路由都放在一个文件里,最终会变得越来越难维护,那实战中我们应该如何维护好路由的编写呢?本节将阐述两种方案。

1、路由分割

所谓路由分割,就是把所有路由按照类别划分,分别维护在不同的文件里。在实际的项目中,通常情况下,一个项目是由多人开发维护的,比如张三只维护货物相关的路由,李四只维护用户相关的路由,如果让两人在一个文件里维护,那随着项目越来越大,接口越来越多,难免会出现不好维护的情况。所以,路由分割就一定程度上解决了这样的问题,让路由易迭代、易维护。

本文提到的实例中有两个类型的路由,一个是货物的,一个是用户的,那么接下来,我们就对这两类路由进行分割。首先,按照类型可以把不同的路由写在不同的文件里,货物的路由文件代码如下:

// routers/goods.jsconst Router = require('koa-router')const router = new Router()// 设置路由前缀router.prefix('/goods')router.get('/getInfo', (ctx, next)=>{ctx.body = "this is koa book."})module.exports = router

用户的路由文件代码如下:

// routers/user.jsconst Router = require('koa-router')const router = new Router()router.prefix('/user')router.get('/getInfo', (ctx, next)=>{ctx.body = "my name is liujianghong."})module.exports = router

每个路由文件里面都使用了一个路由前缀的设置,这样方便分类。每个文件封装了不同类型的路由,接下来要做的就是把这些路由进行整合。Koa源码中有一个非常重要的实现是中间件的合并,其中就使用了koa-compose包,读者可以返回《Koa开发:入门、进阶与实战》一书的第3章复习一下。路由的合并也会用到koa-compose来进行实现,代码如下:

// routers/index.jsconst compose = require('koa-compose')const glob = require('glob')const { resolve } = require('path')registerRouter = () => {let routers = [];// 递归式获取当前文件夹下所有的js文件glob.sync(resolve(__dirname, './', '**/*.js'))// 排除index.js文件,因为这个文件不是具体的路由文件.filter(value => (value.indexOf('index.js') === -1)).forEach(router => {routers.push(require(router).routes())routers.push(require(router).allowedMethods())})return compose(routers)}module.exports = registerRouter

这里可以使用koa-compose来对koa-router进行整合,是因为koa-router里面的routers方法和allowedMethods方法和我们平时用的中间件里面的回调是一样的,读者如果感兴趣的话,可以看一下koa-router的源码。最后实现一个简单的server,即把整合后的路由引进来,代码如下:

// app.jsconst Koa = require('koa')const registerRouter  = require('./routers')const app = new Koa()app.use(registerRouter())app.listen(4000, () => {console.log('server is running, port is 4000')})

运行app.js,我们在浏览器访问http://127.0.0.1:4000/goods/getInfo,效果如图1所示。

b4cd201cd449567eef1a6a91dbe50e10.png 图1 访问货物路由运行结果

访问http://127.0.0.1:4000/user/getInfo,效果如图2所示。 

1efe3c9f39bb3a185b32defe0a256a18.png

图2 访问用户路由运行结果


2、文件路由

根据文件路径来匹配路由,也是实际的项目可能采取的一种方式,我们先了解一下什么是文件路由,比如,现在有这样一个项目,组织结构如图3所示。

d19150c17a3e651bdd0a76ff68ff1413.png 图3 文件路由的项目结构

actions目录下的内容就是匹配路由的,比如前端有一个GET请求http://127.0.0.1:4000/goods/getInfo,那么最终会匹配到actions目录下goods/getInfo.js文件,最终会执行getInfo.js里面的逻辑。这么设计有以下几点优势:

● 依据项目中文件目录就能了解本项目都有哪些路由,不用查看路由文件,非常方便。

● 用文件路径来组织路由,对用户非常友好,便于开发。

接下来我们详细分析这种文件路由该如何实现。总共有两个步骤:第一步,定义goods/getInfo.js和user/getInfo.js两个文件内容,主要是定义一些属性,包括请求的方法类型(GET、POST等)、执行的回调;第二步,把请求的path映射到对应的文件路径上,当请求过来后,能够执行对应的文件内容。接下来看代码如何实现。

1)定义两个文件内容

actions/goods/getInfo.js文件的定义代码如下:

// actions/goods/getInfo.jsmodule.exports = {method: 'GET',  handler: (ctx) => {ctx.body = "this is koa book."}    }

actions/user/getInfo.js文件的定义代码如下:

// actions/user/getInfo.js module.exports = {   method: 'GET',   handler: (ctx) => {     ctx.body = "my name is liujianghong."   }     }

两个文件都定义了两个属性,一个是method,一个是handler。method指的是请求的类型,这里method的配置主要是为了映射到唯一请求,比如请求路径都是/goods/getInfo,那方法类型既可以是GET请求,也可以POST请求,两个请求是不一样的。hander方法就是一个回调方法,用来处理相应的业务逻辑。

2)请求的path映射到对应的文件

首先请求的path可通过context对象来获取,比较方便,主要问题是文件路径如何处理。其实我们可以通过glob这个包来获取所有的文件,然后对路径再做相应的处理即可,代码如下:

const glob = require('glob')const path = require('path')const Koa = require('koa')const app = new Koa()// actions的绝对路径const basePath = path.resolve(__dirname, './actions')// 获取actions目录下所有的js文件,并返回其绝对路径const filesList = glob.sync(path.resolve(__dirname, './actions', '**/*.js'))// 文件路由映射表let routerMap = {}filesList.forEach(item => {// 解构的方式获取,当前文件导出对象中的method属性和handler属性const { method, handler } = require(item)// 获取和actions目录的相对路径,例如:goods/getInfo.jsconst relative = path.relative(basePath, item)// 获取文件后缀.jsconst extname = path.extname(item)// 剔除后缀.js,并在前面加一个"/",例如:/goods/getInfoconst fileRouter = '/' + relative.split(extname)[0]// 连接method,形成一个唯一请求,例如: _GET_/goods/getInfoconst key = '_' + method + '_' + fileRouter// 保存在路由表里routerMap[key] = handler})app.use(async (ctx, next) => {const { path, method } = ctx// 构建和文件路由匹配的形式:_GET_路由const key = '_' + method + '_' + path// 如果匹配到,就执行对应到handlerif (routerMap[key]) {routerMap[key](ctx)} else {ctx.body = 'no this router'}})app.listen(4000, () => {console.log('server is running, port is 4000')})

文件路由书写起来比较优雅,并且可以做到高度可配置,这样对每个请求可以实行个性化定制,我们在Koa实战中也会使用这种方式来做路由,到时候详细讲述企业级别的BFF架构中文件路由该如何设计。

无论是通过中间件的路由分割还是通过文件的路由分割,都在一定程度上能够优化路由的组织方式,方便后续的需求迭代。如果您想要了解更多有关Koa的高级应用,如用户鉴权机制、数据存储、进程管理等,推荐您详细阅读刘江虹老师的新作《Koa开发:入门、进阶与实战》。

作者介绍:刘江虹,字节跳动抖音电商前端架构师,目前主要负责业务架构中工程化等相关方向,拥有多年前端架构工作经验。独立开发过一款可对标Egg的BFF企业级框架,支撑公司线上服务超1000个,全栈前端技术专家,具有丰富的Node实战经验。著有畅销书《React.js实战》。

087db974613317529c80ac2a0b2ff792.png


抽奖规则:在留言区留言为什么想要这本书,随机抽取「2位」理由充分 && 关注比较久 && 留言互动相对多的小伙伴。包邮送出本书。

另外为了鼓励大家多写源码共读笔记,我会在写了5次及以上笔记的作者群里也抽奖送这本书。以后也会有更多福利倾斜。

开奖时间4月18日(周一)晚8点。中奖者在开奖后1天内与我取得联系,否则视为放弃。我会在微信留言区回复中奖人。

中奖者开奖前必须是我的微信好友,且需是前端。羊毛党绕路。

总之最终解释权归我。

记得扫码加我微信 ruochuan12 , 参加源码共读。

600e42f49ccae7499b0308aa49106710.png

02bcea82e55a1bc245b4a192f57ce67a.gif

点击阅读全文购买

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/274740.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

设计模式_设计

设计模式Thanks for my colleague WanChing‘s help to prepare this sharing article. E-Commerce app collects plentiful products from various brands. Each brand has its brand signature colors and public image. This article introduces how we made a single page …

使用 GTD 优化自己的工作和生活

大家好,我是若川。持续组织了8个月源码共读活动,感兴趣的可以点此加我微信 ruochuan12 参与,每周大家一起学习200行左右的源码,共同进步。同时极力推荐订阅我写的《学习源码整体架构系列》 包含20余篇源码文章。历史面试系列。另外…

模仿不再受宠若惊

If you haven’t heard of the Jio-Zoom plagiarism clash, you’re probably living under a rock (which may not be a bad idea given the state of the world right now). The turf war between Jio Meet and Zoom began when the Indian telecom giant ripped off the Chi…

Vue2剥丝抽茧-响应式系统 系列

大家好,我是若川。持续组织了8个月源码共读活动,感兴趣的可以点此加我微信 ruochuan12 参与,每周大家一起学习200行左右的源码,共同进步。同时极力推荐订阅我写的《学习源码整体架构系列》 包含20余篇源码文章。历史面试系列。另外…

word文本样式代码样式_使用文本样式表达创建真相来源

word文本样式代码样式As of After Effects 17.0, you can use expressions to edit text styles in After Effects. Here’s why this would transform your workflow:从After Effects 17.0开始,您可以使用表达式在After Effects中编辑文本样式。 这就是这将改变您的…

前端框架源码解读之Vite

前端工具链十年盘点:https://mp.weixin.qq.com/s/FBxVpcdVobgJ9rGxRC2zfgWebpack、Rollup 、Esbuild、Vite ?webpack: 基于 JavaScript 开发的前端打包构建框架,通过依赖收集,模块解析,生成 chunk,最终输出生成的打包…

hp-ux_UX中的格式塔-或-为什么设计师如此讨厌间距

hp-uxI’ve been lucky so far in my design career to have worked with engineers that seem genuinely interested in learning about design. Perhaps, as mentioned in the title, it’s more about them trying to figure out why it matters so much to us that there i…

JavaScript 数组新增 4 个非破坏性方法!

大家好,我是若川。持续组织了8个月源码共读活动,感兴趣的可以点此加我微信 ruochuan12 参与,每周大家一起学习200行左右的源码,共同进步。同时极力推荐订阅我写的《学习源码整体架构系列》 包含20余篇源码文章。历史面试系列。另外…

自行车改装电动车怎么样_电动车听起来应该是什么样?

自行车改装电动车怎么样The sound of an all-electric car accelerating doesn’t have to sound like a standard combustion engine, It could sound like anything.全电动汽车加速的声音不必听起来像是标准的内燃机,它可以听起来像任何东西。 These were the wor…

谷歌pay破解_Google Pay缺少Google闻名的一件事-UX案例研究

谷歌pay破解Disclaimer: The views expressed in the blog post is purely based on personal experience. It was not influenced by any external factor.When Google launched Tez (now Google Pay) in India during 2017, their primary goal was to design a simple payme…

进阶高级前端,这位大前端架构师一定不能错过

今天给大家介绍一位好朋友:这波能反杀:一位拥有十年工作经验,对学习方法有独到理解的资深大前端架构师。一、博客早在 2017 年初,波神在简书平台以《前端基础进阶》为名,更新了一系列优质文章,获得大量认可…

memcached应用策略(转)

memcached应用策略(转)(2012-04-05 11:10:02) 转载▼标签: memcached 应用策略 it分类: linux_c memcached应用策略memcached 主要的作用是为减轻大访问量对数据库的冲击,所以一般的逻辑是首先从memcached中读取数据&a…

突然讨厌做前端,讨厌代码_为什么用户讨厌重新设计

突然讨厌做前端,讨厌代码重点 (Top highlight)The core of design thinking is to only design something that will bring value and fill the gap in consumer needs. Right? Why else would one design something that no one asked for? While that may be true to some …

那些年我面过的「六年经验」的初级工程师

大家好,我是若川。持续组织了8个月源码共读活动,感兴趣的可以 点此加我微信ruochuan12 参与,每周大家一起学习200行左右的源码,共同进步。同时极力推荐订阅我写的《学习源码整体架构系列》 包含20余篇源码文章。历史面试系列。另外…

更多信息请关注微信公众号_为什么我们更多地关注表面异常?

更多信息请关注微信公众号Don’t you feel lucky to find a single seasoned curly fry in your bunch of plain old boring french fries? Do you remember highlighting important texts of your study materials before the exams? Both situations might seem irrelevant…

eclipse中的汉字极小的解决方案(转载)

eclipse中的汉字极小的解决方案(转载) 可能新装了eclipse后,写java代码的时候发现,写注释的时候发现,汉字小的可怜,网上搜一下,又是改字体又是设置字体大小,试用后发现都不是针对这个的方法。 无奈在自己摸…

面试官经常问的观察者模式如何实现~

大家好,我是若川。持续组织了8个月源码共读活动,感兴趣的可以 点此加我微信ruochuan12 参与,每周大家一起学习200行左右的源码,共同进步。同时极力推荐订阅我写的《学习源码整体架构系列》 包含20余篇源码文章。历史面试系列。另外…

旅行者 问题_门槛项目:没有旅行者回到他的原籍城市。

旅行者 问题Sohini Mukherjee| MFA| Spring 2020Sohini Mukherjee | 外交部| 2020年Spring Artivive app to see the full Artivive应用程序可查看完整的#AR experience.#AR体验。 Prompt:提示: As second semester, first year graduate students, you are at a …

产品经理懂技术=流氓会武术(zz)

最近七年,我都在做互联网产品,其中前五年分别在创业公司和上市公司里,做别人的产品;近两年在创业,做自己的产品。 我的体会是:产品经理需要懂技术,创业者尤其需要。但前提是你总觉得有股憋不住的…

技术人的七大必备特质

大家好,我是若川。持续组织了8个月源码共读活动,感兴趣的可以 点此加我微信ruochuan12 参与,每周大家一起学习200行左右的源码,共同进步。同时极力推荐订阅我写的《学习源码整体架构系列》 包含20余篇源码文章。历史面试系列。另外…