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.js
 const 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.js
 const 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.js
 const 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.js
 const 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.js
 module.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.js
   const relative = path.relative(basePath, item)
   // 获取文件后缀.js
   const extname = path.extname(item)
   // 剔除后缀.js,并在前面加一个"/",例如:/goods/getInfo
   const fileRouter = '/' + relative.split(extname)[0]
   // 连接method,形成一个唯一请求,例如: _GET_/goods/getInfo
   const key = '_' + method + '_' + fileRouter
   // 保存在路由表里
   routerMap[key] = handler
 })


 app.use(async (ctx, next) => {
   const { path, method } = ctx
   // 构建和文件路由匹配的形式:_GET_路由
   const key = '_' + method + '_' + path
   // 如果匹配到,就执行对应到handler
   if (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

点击阅读全文购买

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
本文档介绍了koa-router的使用方法和API,帮助开发者更好地应用koa-router进行路由管理。 koa-router是一个基于koa路由管理器,它提供了一种简单、灵活的方式来定义和处理路由。它支持常见的RESTful API风格,如GET、POST、PUT和DELETE等,同时还支持间件和参数传递等特性。 安装koa-router 在使用koa-router之前,我们需要先安装它。可以通过npm进行安装: ``` npm install koa-router ``` 使用koa-router 在使用koa-router之前,我们需要先引入它: ```javascript const Koa = require('koa'); const Router = require('koa-router'); const app = new Koa(); const router = new Router(); ``` 定义路由koa-router,我们可以通过router对象来定义路由。以下是一个简单的例子: ```javascript router.get('/', async (ctx, next) => { ctx.body = 'Hello World!'; }); router.get('/users', async (ctx, next) => { ctx.body = 'User List!'; }); router.get('/users/:id', async (ctx, next) => { const { id } = ctx.params; ctx.body = `User ${id}`; }); ``` 上面的例子,我们定义了三个路由: - GET /: 返回"Hello World!" - GET /users: 返回"User List!" - GET /users/:id: 返回"User {id}",其:id表示一个参数 使用路由 在定义完路由后,我们需要将它们应用到Koa应用程序: ```javascript app.use(router.routes()); app.use(router.allowedMethods()); ``` 其,`router.routes()`用于将路由应用到应用程序,`router.allowedMethods()`用于处理不支持的HTTP方法。 间件 koa-router还支持间件,可以通过以下方式使用: ```javascript const auth = async (ctx, next) => { if (ctx.isAuthenticated()) { await next(); } else { ctx.status = 401; ctx.body = 'Unauthorized'; } }; router.get('/private', auth, async (ctx, next) => { ctx.body = 'Private Content!'; }); ``` 上面的例子,我们定义了一个间件`auth`,它用于验证用户是否已经通过身份验证。在定义路由时,我们将其作为第二个参数传递给`router.get()`方法,表示只有通过身份验证的用户才能访问该路由。 参数传递 koa-router还支持参数传递,可以通过以下方式使用: ```javascript router.get('/users/:id', async (ctx, next) => { const { id } = ctx.params; const user = await getUserById(id); ctx.body = user; }); ``` 上面的例子,我们使用`:id`作为参数占位符,并通过`ctx.params`获取传递的参数值。 API koa-router的API如下: - router.get(path, middleware): 定义一个GET路由 - router.post(path, middleware): 定义一个POST路由 - router.put(path, middleware): 定义一个PUT路由 - router.delete(path, middleware): 定义一个DELETE路由 - router.patch(path, middleware): 定义一个PATCH路由 - router.head(path, middleware): 定义一个HEAD路由 - router.options(path, middleware): 定义一个OPTIONS路由 - router.all(path, middleware): 定义一个支持所有HTTP方法的路由 - router.use(middleware): 定义一个间件 - router.routes(): 返回应用程序定义的路由 - router.allowedMethods(): 处理不支持的HTTP方法 总结 koa-router是一个灵活、易用的路由管理器,它提供了丰富的特性,如RESTful API风格、间件、参数传递等。通过学习本文档,开发者可以更好地了解koa-router的使用方法和API,从而更好地应用koa-router进行路由管理。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值