安装
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 ⇒ Router
Koa-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 );
支持多个中间件 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('/' , ... ); router.get('/:id' , ... );
router.use([path], middleware) ⇒ Router use
是Router
实例的方法。middleware按照use
定义的顺序,按顺序执行。
param
type
[path]
String
middleware
function
[…]
function
1 2 3 4 5 6 7 8 9 10 11 12 router .use (session()) .use (authorize()); router.use ('/users' , userAuth()); router.use (['/users' , '/admin' ], userAuth()); app.use (router.routes());
router.prefix(prefix) ⇒ Router prefix
是Router
的实例方法。用于设置Router实例的路径前缀。
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 redirect
是Router
的实例方法。
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 param
是Router
的实例方法。为命名的路由参数运行中间件,对于自动加载和验证非常有用。
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();function add_rule (router, rule ) { for (let key in rule) { 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} ` ); } } } function add_rules (router ) { 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 (controller()) app.listen(3000 )
结果如下: