Koa-router 是 koa 的一個路由中間件,它可以將請求的URL和方法(如:GET
、 POST
、 PUT
、 DELETE
等) 匹配到對應的響應程序或頁面。本文將介紹 koa-router 基本配置、使用以及一些參考筆記。
基本配置
創建Koa應用
下面的代碼創建了一個koa web服務,監聽了3000端口,如果訪問 http://localhost:3000/ 將返回 Not Found
,這是因為代碼沒有對請求做任何響應。后面將使用 koa-router 在這個基礎上進行修改,使其支持不同的路由匹配。
// app.js
const Koa = require('koa'); // 引入koa
const app = new Koa(); // 創建koa應用
// 啟動服務監聽本地3000端口
app.listen(3000, () => {
console.log('應用已經啟動,http://localhost:3000');
})
安裝koa-router
$ npm install koa-router --save
使用koa-router
首先,使用 require()
引入 koa-router
,并且對其實例化(支持傳遞參數),然后使用獲取到的路由實例 router
設置一個路徑,將 '/'
匹配到相應邏輯,返回一段HTML 。接著還需要分別調用 router.routes()
和 router.allowedMethods()
來得到兩個中間件,并且調用 app.use()
使用這兩個中間件:
const Koa = require('koa'); // 引入koa
const Router = require('koa-router'); // 引入koa-router
const app = new Koa(); // 創建koa應用
const router = new Router(); // 創建路由,支持傳遞參數
// 指定一個url匹配
router.get('/', async (ctx) => {
ctx.type = 'html';
ctx.body = '<h1>hello world!</h1>';
})
// 調用router.routes()來組裝匹配好的路由,返回一個合并好的中間件
// 調用router.allowedMethods()獲得一個中間件,當發送了不符合的請求時,會返回 `405 Method Not Allowed` 或 `501 Not Implemented`
app.use(router.routes());
app.use(router.allowedMethods({
// throw: true, // 拋出錯誤,代替設置響應頭狀態
// notImplemented: () => '不支持當前請求所需要的功能',
// methodNotAllowed: () => '不支持的請求方式'
}));
// 啟動服務監聽本地3000端口
app.listen(3000, () => {
console.log('應用已經啟動,http://localhost:3000');
})
使用
不同請求方式
Koa-router 請求方式: get
、 put
、 post
、 patch
、 delete
、 del
,而使用方法就是 router.方式()
,比如 router.get()
和 router.post()
。而 router.all()
會匹配所有的請求方法。
當 URL 匹配成功,router
就會執行對應的中間件來對請求進行處理,下面是使用示例:
// ...
// 指定一個url匹配
router.get('/', async (ctx) => {
ctx.type = 'html';
ctx.body = '<h1>hello world!</h1>';
})
.get("/users", async (ctx) => {
ctx.body = '獲取用戶列表';
})
.get("/users/:id", async (ctx) => {
const { id } = ctx.params
ctx.body = `獲取id為${id}的用戶`;
})
.post("/users", async (ctx) => {
ctx.body = `創建用戶`;
})
.put("/users/:id", async (ctx) => {
const { id } = ctx.params
ctx.body = `修改id為${id}的用戶`;
})
.del("/users/:id", async (ctx) => {
const { id } = ctx.params
ctx.body = `刪除id為${id}的用戶`;
})
.all("/users/:id", async (ctx) => {
ctx.body = ctx.params;
});
// ...
從請求參數取值
有些時候需要從請求URL上獲取特定參數,主要分為兩類: params
和 query
。 這兩種參數獲取的方式如下:
params參數
router.get('/:category/:title', (ctx, next) => {
console.log(ctx.params);
// => { category: 'programming', title: 'how-to-node' }
});
query參數
router.get("/users", async (ctx) => {
console.log('查詢參數', ctx.query);
ctx.body = '獲取用戶列表';
})
路由使用中間件
router
還支持使用中間件,并且可以針對特定的URL或者多個URL使用中間件:
// 先后設置兩個中間件
router
.use(session())
.use(authorize());
// 給指定地址使用中間件
router.use('/users', userAuth());
// 給數組里面的地址使用中間件
router.use(['/users', '/admin'], userAuth());
app.use(router.routes());
設置路由前綴
可以通過調用 router.prefix(prefix)
來設置路由的前綴,也可以通過實例化路由的時候傳遞參數設置路由的前綴,比如在 RESTful 接口里面,往往會為接口設置一個 api
前綴,如:
router.prefix('/api')
// 或者
const router = new Router({
prefix: '/api'
})
當然也支持設置參數:
router.prefix('/路徑/:參數')
路由嵌套
有時路由涉及到很多業務模塊,可能需要對模塊進行拆分和嵌套,koa-router 提供了路由嵌套的功能,使用也很簡單,就是創建兩個 Router
實例,然后將被嵌套的模塊路由作為父級路由的中間件使用:
var forums = new Router();
var posts = new Router();
posts.get('/', (ctx, next) => {...});
posts.get('/:pid', (ctx, next) => {...});
forums.use('/forums/:fid/posts', posts.routes(), posts.allowedMethods());
// responds to "/forums/123/posts" and "/forums/123/posts/123"
app.use(forums.routes());
拆分路由
通過路由嵌套可以對路由進行拆分,不同的模塊使用不同的文件,如下面的示例:
app.js
只引入路由入口文件
const Koa = require('koa'); // 引入koa
+ const router = require('./router');
const app = new Koa(); // 創建koa應用
+ app.use(router.routes());
+ app.use(router.allowedMethods());
// 啟動服務監聽本地3000端口
app.listen(3000, () => {
console.log('應用已經啟動,http://localhost:3000');
})
router/user.js
設置了 user
模塊的路由,并且導出:
const Router = require('koa-router');
const router = new Router();
router.get("/", async (ctx) => {
console.log('查詢參數', ctx.query);
ctx.body = '獲取用戶列表';
})
.get("/:id", async (ctx) => {
const { id } = ctx.params
ctx.body = `獲取id為${id}的用戶`;
})
.post("/", async (ctx) => {
ctx.body = `創建用戶`;
})
.put("/:id", async (ctx) => {
const { id } = ctx.params
ctx.body = `修改id為${id}的用戶`;
})
.del("/:id", async (ctx) => {
const { id } = ctx.params
ctx.body = `刪除id為${id}的用戶`;
})
.all("/users/:id", async (ctx) => {
ctx.body = ctx.params;
});
module.exports = router;
router/index.js
導出了整個路由模塊:
const Router = require('koa-router');
const user = require('./user');
const router = new Router();
// 指定一個url匹配
router.get('/', async (ctx) => {
ctx.type = 'html';
ctx.body = '<h1>hello world!</h1>';
})
router.use('/user', user.routes(), user.allowedMethods());
module.exports = router;
筆記
命名路由
router.get('user', '/users/:id', (ctx, next) => {
// ...
});
router.url('user', 3);
// => "/users/3"
通過 ctx._matchedRoute
獲得匹配的路由,通過 ctx._matchedRouteName
獲得匹配的路由名。
設置多個中間件
router.get(
'/users/:id',
(ctx, next) => {
return User.findOne(ctx.params.id).then(function(user) {
ctx.user = user;
next();
});
},
ctx => {
console.log(ctx.user);
// => { id: 17, name: "Alex" }
}
);
路由重定向
使用 router.redirect(source, destination, [code])
可以對路由進行重定向,例子:
router.redirect('/login', 'sign-in');
等價于:
router.all('/login', ctx => {
ctx.redirect('/sign-in');
ctx.status = 301;
});