全棧專案|小書架|伺服器開發-Koa全域性路由實現
什麼是路由
路由就是具體的訪問路徑,指向特定的功能模組。一個
api
介面是由ip(域名)+埠號
+路徑組成,例如 :https://www.npmjs.com/package/koa-router
就是一個路由,指向了koa-router
的npm
頁面。
為什麼需要 koa-router 路由
當然不需要koa-router
也能實現路由功能,通過ctx.request.path
去指定路徑實現。例子如下:
const koa = require('koa2')
const app = new koa()
app.use(async (ctx,next) => {
if (ctx.request.path === '/' ) { // 首頁
ctx.response.status = 200
ctx.response.body = 'index'
} else if (ctx.request.path === '/list') { // 列表頁
ctx.response.status = 200
ctx.response.body = 'list'
} else {
ctx.throw(404,'Not found') // 404
}
await next()
})
app.listen(3000)
複製程式碼
以上程式碼只是實現兩個介面,就寫了不少程式碼,而寫是多層的判斷程式碼,可讀性已經很差了,這時候怎麼辦?
是不是可以將以上程式碼抽取出去,通過中介軟體的方式去實現。
結果是可以的,koa-router
就是這樣做的。使用koa-router
實現的例子如下:
- app.js 入口
- urls/home.js home 頁面的路由
app.js
的程式碼如下
// 路由模組使用前需要先安裝和例項化
const Router = require('koa-router')
const router = new Router()
// 首頁
app.use(async (ctx,next) => {
if (ctx.request.path === '/') {
ctx.response.status = 200
ctx.response.body = 'index'
}
await next()
})
// 其他頁面通過 router 載入
let urls = fs.readdirSync(__dirname + '/urls')
urls.forEach((element) => {
let module = require(__dirname + '/urls/' + element)
/*
urls 下面的每個檔案負責一個特定的功能,分開管理
通過 fs.readdirSync 讀取 urls 目錄下的所有檔名,掛載到 router 上面
*/
router.use('/' + element.replace('.js',''),module.routes(),module.allowedMethods())
})
app.use(router.routes())
複製程式碼
urls/home.js
的程式碼如下
const Router = require('koa-router')
const home = new Router()
// /home
home.get('/',async (ctx,next) => {
ctx.response.status = 200
ctx.response.body = 'home'
await next()
})
// home/list
home.get('/list',next) => {
ctx.response.status = 200
ctx.response.body = 'home-list'
await next()
})
module.exports = home
複製程式碼
通過以上程式碼基本已經實現了全域性路由的功能
了,剩下得就是在urls
包下建立對應的檔案即可,參考home.js
即可。
但是這裡的程式碼還是不夠完美,app.js
作為入口檔案,這裡的程式碼還是有點多了;而且首頁和home
的路由是分開來實現的。再而且urls
路徑是固定的,後續資料夾名稱或者位置改變都會出現問題。
那麼如何實現呢? 這裡介紹一種思路:
- 將
app.js
中的程式碼抽取出來,讓app.js
儘量簡單 - 將首頁和其他頁面都在全域性路由中實現
優雅的全域性路由實現
通過npm
引入require-directory
require-directory npm
包的作用是:
遞迴地遍歷指定目錄,對每個檔案進行require()
這裡也是利用了這個包去實現的。具體實現如下:
- 在
core
目錄下建立InitManager.js
const requireDirectory = require('require-directory')
const Router = require('koa-router')
/**
* 載入全域性路由
*/
static initLoadRouters(app){
// 載入工作目錄下的 app/api 下的路徑
const apiDirectory = `${process.cwd()}/app/api`
// 引數:第一個引數固定引數module
// 第二個引數要載入的模組的檔案路徑
// 第三個引數:每次載入一個引數執行的函式
requireDirectory(module,apiDirectory,{
visit: whenLoadModule
})
function whenLoadModule(obj) {
if(obj instanceof Router ){
app.use(obj.routes())
}
}
}
module.exports = InitManager
複製程式碼
從上面的實現方式可以看出這裡使用了process.cwd()
獲取路徑,而原有的程式碼中是通過__dirname
去獲取路徑,那麼二者有什麼區別呢?
NodeJs
中process.cwd()
與__dirname
的區別process.cwd()
是當前執行node
命令時候的資料夾地址 ——工作目錄,保證了檔案在不同的目錄下執行時,路徑始終不變__dirname
是被執行的js
檔案的地址 ——檔案所在目錄
- 在
app.js
中載入這個方法即可。
const app = new Koa()
InitManager.initLoadRouters(app)
複製程式碼
- 在
app/api
下建立相應的介面檔案即可,如home.js
諮詢請加微信:輕撩即可。