Koa在实际的业务场景中,路由如何做分割?【文末留言送书】
大家好,我是若川。文末留言送書,具體規(guī)則文末說明。另外為了鼓勵大家多寫源碼共讀筆記,我會在寫了5次及以上筆記的作者群里也抽獎送這本書。以后也會有更多福利傾斜。
導(dǎo)讀:Koa是一個Node框架,在Node開源社區(qū)中,Koa的使用范圍非常廣,掌握Koa的使用方法,就能輕松應(yīng)對業(yè)界的一些BFF框架。本文介紹Koa在實際的業(yè)務(wù)場景中,路由如何做分割。
?
作者:劉江虹
來源:華章計算機(jī)(hzbook_jsj)
在實際的復(fù)雜業(yè)務(wù)場景中,簡單的路由堆砌會使得路由文件越來越大,隨著后續(xù)的項目不斷迭代,開發(fā)人員的不斷更替,如果所有的路由都寫在一個文件里,會使得路由模塊變得越來越難維護(hù)。
那么,Koa的項目要如何去解決路由難維護(hù)的問題呢?對于這個問題,由抖音電商前端架構(gòu)師撰寫的《Koa開發(fā):入門、進(jìn)階與實戰(zhàn)》給出了很好的解決方案,下面讓我們結(jié)合這本書的內(nèi)容來詳細(xì)看一看Koa中路由的使用技巧。
在介紹路由分割以及文件路由之前,我們回憶一下koa-router這個中間件的使用。假如需要兩個路由,一個是獲取貨物信息,一個是獲取用戶信息,那用koa-router實現(xiàn)的代碼應(yīng)該是這樣的:
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')})這樣的寫法相信讀者應(yīng)該已經(jīng)掌握了,但這樣寫其實有個弊端,如果在一個實際的項目中,Node.js層的接口可能會很多,所有的路由都放在一個文件里,最終會變得越來越難維護(hù),那實戰(zhàn)中我們應(yīng)該如何維護(hù)好路由的編寫呢?本節(jié)將闡述兩種方案。
1、路由分割
所謂路由分割,就是把所有路由按照類別劃分,分別維護(hù)在不同的文件里。在實際的項目中,通常情況下,一個項目是由多人開發(fā)維護(hù)的,比如張三只維護(hù)貨物相關(guān)的路由,李四只維護(hù)用戶相關(guān)的路由,如果讓兩人在一個文件里維護(hù),那隨著項目越來越大,接口越來越多,難免會出現(xiàn)不好維護(hù)的情況。所以,路由分割就一定程度上解決了這樣的問題,讓路由易迭代、易維護(hù)。
本文提到的實例中有兩個類型的路由,一個是貨物的,一個是用戶的,那么接下來,我們就對這兩類路由進(jìn)行分割。首先,按照類型可以把不同的路由寫在不同的文件里,貨物的路由文件代碼如下:
//?routers/goods.jsconst?Router?=?require('koa-router')const?router?=?new?Router()//?設(shè)置路由前綴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每個路由文件里面都使用了一個路由前綴的設(shè)置,這樣方便分類。每個文件封裝了不同類型的路由,接下來要做的就是把這些路由進(jìn)行整合。Koa源碼中有一個非常重要的實現(xiàn)是中間件的合并,其中就使用了koa-compose包,讀者可以返回《Koa開發(fā):入門、進(jìn)階與實戰(zhàn)》一書的第3章復(fù)習(xí)一下。路由的合并也會用到koa-compose來進(jìn)行實現(xiàn),代碼如下:
//?routers/index.jsconst?compose?=?require('koa-compose')const?glob?=?require('glob')const?{?resolve?}?=?require('path')registerRouter?=?()?=>?{let?routers?=?[];//?遞歸式獲取當(dāng)前文件夾下所有的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進(jìn)行整合,是因為koa-router里面的routers方法和allowedMethods方法和我們平時用的中間件里面的回調(diào)是一樣的,讀者如果感興趣的話,可以看一下koa-router的源碼。最后實現(xiàn)一個簡單的server,即把整合后的路由引進(jìn)來,代碼如下:
// 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')})運(yùn)行app.js,我們在瀏覽器訪問http://127.0.0.1:4000/goods/getInfo,效果如圖1所示。
?圖1 訪問貨物路由運(yùn)行結(jié)果
訪問http://127.0.0.1:4000/user/getInfo,效果如圖2所示。?
圖2 訪問用戶路由運(yùn)行結(jié)果
2、文件路由
根據(jù)文件路徑來匹配路由,也是實際的項目可能采取的一種方式,我們先了解一下什么是文件路由,比如,現(xiàn)在有這樣一個項目,組織結(jié)構(gòu)如圖3所示。
?圖3 文件路由的項目結(jié)構(gòu)
actions目錄下的內(nèi)容就是匹配路由的,比如前端有一個GET請求http://127.0.0.1:4000/goods/getInfo,那么最終會匹配到actions目錄下goods/getInfo.js文件,最終會執(zhí)行g(shù)etInfo.js里面的邏輯。這么設(shè)計有以下幾點(diǎn)優(yōu)勢:
●?依據(jù)項目中文件目錄就能了解本項目都有哪些路由,不用查看路由文件,非常方便。
●?用文件路徑來組織路由,對用戶非常友好,便于開發(fā)。
接下來我們詳細(xì)分析這種文件路由該如何實現(xiàn)。總共有兩個步驟:第一步,定義goods/getInfo.js和user/getInfo.js兩個文件內(nèi)容,主要是定義一些屬性,包括請求的方法類型(GET、POST等)、執(zhí)行的回調(diào);第二步,把請求的path映射到對應(yīng)的文件路徑上,當(dāng)請求過來后,能夠執(zhí)行對應(yīng)的文件內(nèi)容。接下來看代碼如何實現(xiàn)。
1)定義兩個文件內(nèi)容
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方法就是一個回調(diào)方法,用來處理相應(yīng)的業(yè)務(wù)邏輯。
2)請求的path映射到對應(yīng)的文件
首先請求的path可通過context對象來獲取,比較方便,主要問題是文件路徑如何處理。其實我們可以通過glob這個包來獲取所有的文件,然后對路徑再做相應(yīng)的處理即可,代碼如下:
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 => {// 解構(gòu)的方式獲取,當(dāng)前文件導(dǎo)出對象中的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// 構(gòu)建和文件路由匹配的形式:_GET_路由const key = '_' + method + '_' + path// 如果匹配到,就執(zhí)行對應(yīng)到handlerif (routerMap[key]) {routerMap[key](ctx)} else {ctx.body = 'no this router'}})app.listen(4000, () => {console.log('server is running, port is 4000')})文件路由書寫起來比較優(yōu)雅,并且可以做到高度可配置,這樣對每個請求可以實行個性化定制,我們在Koa實戰(zhàn)中也會使用這種方式來做路由,到時候詳細(xì)講述企業(yè)級別的BFF架構(gòu)中文件路由該如何設(shè)計。
無論是通過中間件的路由分割還是通過文件的路由分割,都在一定程度上能夠優(yōu)化路由的組織方式,方便后續(xù)的需求迭代。如果您想要了解更多有關(guān)Koa的高級應(yīng)用,如用戶鑒權(quán)機(jī)制、數(shù)據(jù)存儲、進(jìn)程管理等,推薦您詳細(xì)閱讀劉江虹老師的新作《Koa開發(fā):入門、進(jìn)階與實戰(zhàn)》。
作者介紹:劉江虹,字節(jié)跳動抖音電商前端架構(gòu)師,目前主要負(fù)責(zé)業(yè)務(wù)架構(gòu)中工程化等相關(guān)方向,擁有多年前端架構(gòu)工作經(jīng)驗。獨(dú)立開發(fā)過一款可對標(biāo)Egg的BFF企業(yè)級框架,支撐公司線上服務(wù)超1000個,全棧前端技術(shù)專家,具有豐富的Node實戰(zhàn)經(jīng)驗。著有暢銷書《React.js實戰(zhàn)》。
?
抽獎規(guī)則:在留言區(qū)留言為什么想要這本書,隨機(jī)抽取「2位」理由充分 && 關(guān)注比較久 && 留言互動相對多的小伙伴。包郵送出本書。
另外為了鼓勵大家多寫源碼共讀筆記,我會在寫了5次及以上筆記的作者群里也抽獎送這本書。以后也會有更多福利傾斜。
開獎時間4月18日(周一)晚8點(diǎn)。中獎?wù)咴陂_獎后1天內(nèi)與我取得聯(lián)系,否則視為放棄。我會在微信留言區(qū)回復(fù)中獎人。
中獎?wù)唛_獎前必須是我的微信好友,且需是前端。羊毛黨繞路。
總之最終解釋權(quán)歸我。
記得掃碼加我微信 ruochuan12 , 參加源碼共讀。
點(diǎn)擊閱讀全文購買
總結(jié)
以上是生活随笔為你收集整理的Koa在实际的业务场景中,路由如何做分割?【文末留言送书】的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 标签体系实施架构
- 下一篇: mysql打开注册表命令_怎么打开注册表