koa-router 学习笔记

安装

1
pm install koa-router

Router

new Router([opts])

param type description
[opts] Object
[opts.prefix] String prefix router paths
1
2
3
4
5
6
7
8
9
10
11
var Koa = require('koa');
var Router = require('koa-router');
var app = new Koa();
var router = new Router();
router.get('/', async (ctx, next) =>{
ctx.body = 'we are at home!';
});
app
.use(router.routes())
.use(router.allowedMethods());
app.listen(3000)

路径匹配的时候,不会把查询字符串考虑在内。比如,/index?param=xyz 匹配路径为 /index

HTTP动词方法

router.get|put|post|patch|delete|del ⇒ RouterKoa-router实例提供一系列动词方法,即一种HTTP动词对应一种方法。

1
2
3
4
5
6
7
8
router
.get('/', async (ctx, next) => {
ctx.body = 'Hello World!';
})
.post('/users', async (ctx, next) => {...})
.put('/users/:id', async (ctx, next) => {...})
.del('/users/:id', async (ctx, next) => {...})
.all('/users/:id', async (ctx, next) => {...})

router.all()用于表示上述所有的动词方法

1
2
3
router.get('/', async (ctx,next) => {
ctx.body = 'Hello World!';
});

上面代码中,router.get方法的第一个参数是根路径,第二个参数是对应的函数方法。

路由参数

我们可以通过ctx.params得到URL参数

1
2
3
4
router.get('/:category/:title', function (ctx, next) {
console.log(ctx.params);
// => { category: 'programming', title: 'how-to-node' }
});

当一个路由被匹配到时,他的路径被存在ctx._matchedRoute,并且如果路由被命名了,它的名字存储在ctx._matchedRouteName
路由路径将被使用path-to-regexp翻译为规则的表达式。查询字符串在匹配请求时不考虑在内。

Named routes

重命名路由使得在开发过程中更容易重命名url

1
2
3
4
5
6
router.get('user', '/users/:id', function (ctx, next) {
// ...
});

router.url('user', 3);
// => "/users/3"

支持多个中间件

1
2
3
4
5
6
7
8
9
10
11
12
13
router.get(
'/users/:id',
function (ctx, next) {
return User.findOne(ctx.params.id).then(function(user) {
ctx.user = user;
return next();
});
},
function (ctx) {
console.log(ctx.user);
// => { id: 17, name: "Alex" }
}
);

嵌套路由

1
2
3
4
5
6
7
8
9
const forums = new Router();
const posts = new Router();

posts.get('/', function (ctx, next) {...});
posts.get('/:pid', function (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());

路由前缀

1
2
3
4
5
6
var router = new Router({
prefix: '/users'
});

router.get('/', ...); // responds to "/users"
router.get('/:id', ...); // responds to "/users/:id"

router.use([path], middleware) ⇒ Router

useRouter实例的方法。middleware按照use定义的顺序,按顺序执行。

param type
[path] String
middleware function
[…] function
1
2
3
4
5
6
7
8
9
10
11
12
// session middleware will run before authorize
router
.use(session())
.use(authorize());

// use middleware only with given path
router.use('/users', userAuth());

// or with an array of paths
router.use(['/users', '/admin'], userAuth());

app.use(router.routes());

router.prefix(prefix) ⇒ Router

prefixRouter的实例方法。用于设置Router实例的路径前缀。

param type
prefix String
1
router.prefix('/things/:thing_id')

router.allowedMethods([options]) ⇒ function

allowedMethods处理的业务是当所有路由中间件执行完成之后,若ctx.status为空或者404的时候,丰富response对象的header头.。

allowedMethods 应用场景

  • 全局应用
1
2
3
4
5
6
7
8
var Koa = require('koa');
var Router = require('koa-router');

var app = new Koa();
var router = new Router();

app.use(router.routes());
app.use(router.allowedMethods());

这是官方文档的推荐用法,我们可以看到router.allowedMethods()用在了路由匹配router.routes()之后,所以在当所有路由中间件最后调用.此时根据ctx.status设置response响应头。

  • 局部应用
    也可以用在路由级的中间件上。
    1
    2
    3
    4
    5
    6
    7
    var Koa = require('koa');
    var Router = require('koa-router');

    var app = new Koa();
    var router = new Router();
    router.use('/test',router.allowedMethods())
    app.use(router.routes());

这时候只有当请求路径匹配到了/test才会执行allowedMethods,然后根据ctx.status设置response响应头。

当然,如果我们不设置router.allowedMethods()在表现上除了ctx.status不会自动设置,以及response header中不会加上Allow之外,不会造成其他影响。
如果要设置,建议按照官方的写法,搞成全局的,路由级别的配置感觉很鸡肋。

router.redirect(source, destination, code) ⇒ Router

redirectRouter的实例方法。

param type description
source String URL or route name.
destination String URL or route name.
code Number HTTP status code (default: 301).

Redirect source to destination URL with optional 30x status code.
Both source and destination can be route names.

1
router.redirect('/login', 'sign-in');

This is equivalent to:

1
2
3
4
router.all('/login', function (ctx) {
ctx.redirect('/sign-in');
ctx.status = 301;
});

router.param(param, middleware) ⇒ Router

paramRouter的实例方法。为命名的路由参数运行中间件,对于自动加载和验证非常有用。

param type
param String
middleware function
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
router
.param('user', function (id, ctx, next) {
ctx.user = users[id];
if (!ctx.user) return ctx.status = 404;
return next();
})
.get('/users/:user', function (ctx) {
ctx.body = ctx.user;
})
.get('/users/:user/friends', function (ctx) {
return ctx.user.getFriends().then(function(friends) {
ctx.body = friends;
});
})
// /users/3 => {"id": 3, "name": "Alex"}
// /users/3/friends => [{"id": 4, "name": "TJ"}]

Router.url(path, params) ⇒ String

Generate URL from url pattern and given params.

param type description
path String url pattern
params Object url parameters
1
2
const url = Router.url('/users/:id', {id: 1});
// => "/users/1"

路由重构:

每个 url 对应一个规则,如果全部放在 app.js 中会造成代码紊乱且难以理解。因此重构整个项目,项目文件结构如下:

项目文件结构
index.js 内容如下:

1
2
3
4
5
6
const homepage = async (ctx, next) =>{
ctx.body = 'we are at home!';
}
module.exports = {
'GET /': homepage
};

user.js内容如下:

1
2
3
4
5
6
const userpage = async (ctx, next) =>{
ctx.body = 'we are at user!';
};
module.exports = {
'GET /user': userpage
};

require(‘controller/index’) 时,会得到一个包含了规则的对象 {'GET /': homepage} 其中,GET 表示 GET 方法 / 表示解析路径,homepage 是针对这个路径所做的操作。解析规则由 controller.js 的 add_rule 方法实现。
controller.js 内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
const fs = require('fs')
const Router = require('koa-router');
const router = new Router();
// 解析规则 {'GET /': homepage}
function add_rule(router, rule) {
for (let key in rule) {
// key = 'GET /' rule = {'GET /': homepage}
if (key.startsWith('GET ')) {
let path = key.substring(4);
router.get(path, rule[key]);
console.log(`register URL mapping: GET ${path}`);
} else if (key.startsWith('POST ')) {
let path = key.substring(5);
router.post(path, rule[key]);
console.log(`register URL mapping: POST ${path}`);
} else {
console.log(`invalid URL: ${key}`);
}
}
}
//自动导入controller文件夹下所有的路由规则
function add_rules(router) {
// 得到 /controller 所有以js结尾的文件
let files = fs.readdirSync(__dirname + '/controller');
let js_files = files.filter((f) => {
return f.endsWith('.js');
});
// 添加规则
for (let f of js_files) {
console.log(`process controller: ${f}...`);
let rule = require(__dirname + '/controller/' + f);
add_rule(router, rule);
}
}
module.exports = function () {
add_rules(router);
return router.routes();
};

app.js 内容如下:

1
2
3
4
5
6
const Koa = require('koa');
const app = new Koa();
const controller = require('./controller');
//app.use(router.routes())
app.use(controller())
app.listen(3000)

结果如下:

路由结果

×

纯属好玩

扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

文章目录
  1. 1. 安装
  2. 2. Router
  3. 3. HTTP动词方法
  4. 4. 路由参数
  5. 5. Named routes
  6. 6. 支持多个中间件
  7. 7. 嵌套路由
  8. 8. 路由前缀
  9. 9. router.use([path], middleware) ⇒ Router
  10. 10. router.prefix(prefix) ⇒ Router
  11. 11. router.allowedMethods([options]) ⇒ function
    1. 11.1. allowedMethods 应用场景
  12. 12. router.redirect(source, destination, code) ⇒ Router
  13. 13. router.param(param, middleware) ⇒ Router
  14. 14. Router.url(path, params) ⇒ String
  15. 15. 路由重构:
,