閱讀目錄
一:理解koa-router一般的路由
koa-router是koa的路由庫,什么是路由庫呢?比如當我們訪問 http://localhost:3001/ 的時候,瀏覽器就會顯示index頁面的內容(一般默認是index)。如果當用戶訪問 http://localhost:3001/home 的時候,瀏覽器就會顯示home頁面的內容。
假如要實現上述功能,如果我們不使用 koa-router 或者其他路由中間件的話,我們一般需要在app.js如下代碼編寫:
const Koa = require('koa');
const app = new Koa();
const route = (ctx, next) => {
console.log(ctx.path);
switch (ctx.path) {
case '/':
ctx.body = '<h1>歡迎光臨index page 頁面</h1>';
break;
case '/home':
ctx.body = '<h1>歡迎光臨home頁面</h1>';
break;
default:
// 404頁面
return;
}
}
app.use(route);
app.listen(3001, () => {
console.log('3001 server start....');
});
然后我們在node命令行中 執行 node app.js 的時候就啟動服務器。
當我們訪問 http://localhost:3001/ 的時候,頁面顯示index page 信息,如下圖所示:

當我們訪問 http://localhost:3001/home 的時候,就顯示 歡迎光臨home頁面的信息。如下圖所示:

這種方式不是很好,當我們項目變得很大的時候,我們需要編寫很多 switch-case 這樣的語句,代碼變得更加耦合,並且當我需要對某個路由要加一個中間件過濾下的時候,這種方式並不好處理。並且當項目非常大的時候,我們不想把所有的路由編寫的一個app.js 頁面的時候,我們需要寫到routes文件夾下多個js里面去,也就是說對路由進行分層級的時候,這樣做的目的就是想讓以后項目路由管理更加方便。那么目前的app.js中的switch-case 這種方式不支持了,因此我們這個時候就需要koa-router這樣的中間件來做這件事情了哦。
因此我們現在需要安裝 koa-router 模塊了。命令如下:
npm install --save koa-router
通過 npm install supervisor --save-dev 安裝supervisor模塊, 用於node熱啟動.
package.json 代碼如下:
{ "name": "routers", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "start": "supervisor app.js" }, "author": "", "license": "ISC", "devDependencies": { "koa": "^2.7.0", "koa-router": "^7.4.0", "supervisor": "^0.12.0" } }
然后我們把app.js 代碼改成如下了:
const Koa = require('koa');
const app = new Koa();
const router = require('koa-router')();
// 添加路由
router.get('/', ctx => {
ctx.body = '<h1>歡迎光臨index page 頁面</h1>';
});
router.get('/home', ctx => {
ctx.body = '<h1>歡迎光臨home頁面</h1>';
});
router.get('/404', ctx => {
ctx.body = '<h1>404...</h1>'
});
// 加載路由中間件
app.use(router.routes());
app.listen(3001, () => {
console.log('server is running at http://localhost:3001');
});
同樣在node命令行中 運行命令 node app.js, 然后在瀏覽器下訪問 http://localhost:3001/ 或 http://localhost:3001/home 或 http://localhost:3001/404 的時候就會加載到對應路由的頁面了。
如上是koa-router 中get方法請求,koa-router也支持處理其他的請求方法,如下:
router.post('/users', ctx => {
// ....
})
.put('/user/:id', ctx => {
// ....
})
.del('/user/:id', ctx => {
// ....
})
.all('/user/:id', ctx => {
// ....
});
如上demo實列中,我們可以看到有一個all方法,該方法通常用於匹配一組路由或者全部路由可以做一些統一的設置操作。
const Koa = require('koa');
const app = new Koa();
const router = require('koa-router')();
// 添加路由
router.get('/', (ctx, next) => {
ctx.body = '<h1>歡迎光臨index page 頁面</h1>';
next();
});
router.get('/home', ctx => {
ctx.body = '<h1>歡迎光臨home頁面</h1>';
});
router.get('/404', ctx => {
ctx.body = '<h1>404...</h1>'
});
// all 方法
router.all('/', (ctx, next) => {
console.log('match "all" method');
next();
});
// 加載路由中間件
app.use(router.routes());
app.listen(3001, () => {
console.log('server is running at http://localhost:3001');
});
如上代碼,當我們運行 http://localhost:3001/ 刷新的時候,可以看到 在node命令行中也會打印 all方法的信息,但是要打印該信息的時候,有一個前提就是上一個中間件必須 next() 執行下,才會執行到下一個中間件上來,否則的話,all方法內部的代碼也不會執行的。
二:理解koa-router命名路由
如下代碼來簡單的理解koa-router命名路由了。當我們在瀏覽器訪問 http://localhost:3001/users/2 的時候,會打印 ctx.params = {'id': 2};並且會顯示 'hello world';
const Koa = require('koa');
const app = new Koa();
const router = require('koa-router')();
// 添加命名路由
router.get('user', '/users/:id', (ctx, next) => {
// 當我們在瀏覽器訪問 http://localhost:3001/users/2 的時候,會打印 ctx.params = {'id': 2}
console.log(ctx.params); // { id: '2' }
ctx.body = 'hello world';
});
// 加載路由中間件
app.use(router.routes());
app.listen(3001, () => {
console.log('server is running at http://localhost:3001');
});
三:理解koa-router多個中間件使用
koa-router支持路由多個中間件的處理,通過這個特性,我們能夠為一個路由添加中間件進行做一些操作的事情。比如如下代碼:
const Koa = require('koa');
const app = new Koa();
const router = require('koa-router')();
// 添加命名路由
router.get('user', '/users/:id', (ctx, next) => {
ctx.body = 'hello world';
// 比如一個異步的操作,執行一些處理
setTimeout(() => {
ctx.user = {'id': 11};
next(); // 把執行權轉交給下一個中間件
}, 100);
}, (ctx, next) => {
// 在該中間件可以對數據進行一些操作等事情,
console.log(ctx.user); // 會打印 {'id': 11}
});
// 加載路由中間件
app.use(router.routes());
app.listen(3001, () => {
console.log('server is running at http://localhost:3001');
});
當我們在瀏覽器運行 http://localhost:3001/users/1 的時候,會顯示 'hello world'文案,並且在node命令行中會打印 {'id': 11}。
四:理解koa-router嵌套路由
我們可以在我們項目中定義很多路由,然后把這些路由組裝起來。最后我們訪問這些路由的時候,都可以支持。什么意思呢?
我們來簡單的做個demo。如下代碼:
const Koa = require('koa');
const app = new Koa();
// 初始化 router1
const router1 = require('koa-router')();
// 初始化 router2
const router2 = require('koa-router')();
// 使用router1做一些事情
router1.get('/', (ctx, next) => {
ctx.body = 'router1';
next();
});
router1.get('/:id', (ctx, next) => {
console.log(22222222);
console.log(ctx.params);
next();
});
// 使用router2嵌套router1
router2.use('/user/:id/xxx', router1.routes(), router1.allowedMethods());
// 加載路由中間件
app.use(router2.routes());
app.listen(3001, () => {
console.log('server is running at http://localhost:3001');
});
當我們訪問 http://localhost:3001/user/1/xxx 這個的時候,就可以匹配到 第一個 router1.get('/', (ctx, next) => {}) 這個路由到,當我們訪問 http://localhost:3001/user/1/xxx/x 的時候,就可以匹配到 router1.get('/:id', (ctx, next) => {}) 這個路由到了,其中/:id 就是命名路由了。不管是 /x 還是 /(任意的路徑都是支持的)。也就是說 router1路由嵌套到router2路由里面了,只要訪問 router2中的路由路徑'http://localhost:3001/' + '/user/:id/xxx' 這樣的路徑的時候,就可以自動把router1的路徑匹配到。也就是可以理解 router2是路由路徑的前綴。
五:分割路由文件
比如現在項目的目錄結構如下:
|----- 項目 | |-- node_modules # 依賴的包文件 | |-- routes # 所有的路由文件 | | |-- index.js # 路由入口文件 | | |-- router1.js # router1.js 路由文件 | | |-- router2.js # router2.js 路由文件 | |-- app.js # 項目啟動的文件 | |-- package.json
如上目錄結構,app.js 文件是啟動代碼文件,代碼如下:
const Koa = require('koa');
const app = new Koa();
const router = require('./routes/index');
// 加載路由中間件
app.use(router.routes(), router.allowedMethods());
app.listen(3001, () => {
console.log('server is running at http://localhost:3001');
});
routes 文件夾包含所有的路由文件,routes/index.js 是路由的入口路由文件,在app.js 會引入該文件,代碼如上,該文件的作用是讀取所有的路由的文件,並且對每個路由進行注冊。
routes/index.js 代碼如下:
const router = require('koa-router')();
const fs = require('fs');
const path = require('path');
const files = fs.readdirSync(__dirname);
/*
/^[^\.].*\.js/ 該正則匹配以.js末尾的文件,包括比如: a.js,
/xx/yy/x.js 類似的多個目錄文件,只要以 .js 末尾的即可。
/^[^\.].*\.js$/.test('a.js'); // true
/^[^\.].*\.js$/.test('/xx/yy/a.js'); // true
*/
files.filter(file => ~file.search(/^[^\.].*\.js$/)).forEach(file => {
// 獲取文件名 比如 xx.js 這樣的,截取 file.substr(0, file.length - 3); 因為 .js 長度為3
const fileName = file.substr(0, file.length - 3);
/*
獲取每個路由的全局路徑,比如文件夾 routes下的 router1.js.
router1.js 代碼如下:
const router = require('koa-router')();
router.get('/', (ctx, next) => {
ctx.body = 'hello world';
});
router.get('/home', (ctx, next) => {
ctx.body = '歡迎光臨home頁面';
});
module.exports = router;
然后對每個路由進行注冊
*/
const fileEntity = require(path.join(__dirname, file));
if (fileName !== 'index') {
router.use(`/${fileName}`, fileEntity.routes(), fileEntity.allowedMethods());
}
});
module.exports = router;
routes/router1.js 是其中一個路由文件,代碼如下:
const router = require('koa-router')();
router.get('/', (ctx, next) => {
ctx.body = 'hello world';
});
router.get('/home', (ctx, next) => {
ctx.body = '歡迎光臨home頁面';
});
module.exports = router;
routes/router2.js 是另外一個路由文件,代碼如下:
const router = require('koa-router')();
router.get('/', (ctx, next) => {
ctx.body = '已經進入router2頁面了';
});
router.get('/detail', (ctx, next) => {
ctx.body = '已經進入詳情頁面了';
});
module.exports = router;
當我們訪問 http://localhost:3001/router1 的時候,會打印 "hello world", 如下圖所示:

當我們訪問 http://localhost:3001/router1/home 的時候,會打印 "歡迎光臨home頁面", 如下圖所示:

當我們訪問 http://localhost:3001/router2 的時候,會打印出 "已經進入router2頁面了", 如下圖所示:

當我們訪問 http://localhost:3001/router2/detail 的時候,會打印出 "已經進入詳情頁面了", 如下圖所示:

