特性
- express风格的路由(
app.get
、app.put
、app.post
等) - 具名的URL参数
- 通过URL生成具名路由
- 匹配指定主机的路由
- 可以响应OPTIONS请求
- 支持405 Not Allowed 和 501 Not Implemented方法
- 路由中间件
- 支持嵌套路由
- 支持
async/await
语法
迁移到 7 / Koa 2
- API已经更改,以适配koa 2 基于promise的中间件签名。更多信息,请查看koa 2. x readme。
- 中间件现在按照
.use()
(或.get()
等)声明的顺序运行,这与Express 4 API相匹配。
安装
npm:
npm install @koa/router
Typescript支持
npm install @types/koa__router
路由
类型:导出的class类
创建一个新的路由实例
new Router([opts])
参数 | 类型 | 描述 |
---|---|---|
[opts] | Object | |
[opts.prefix] | String | 路由路径前缀 |
[opts.exclusive] | Boolean | 当有多个路由匹配,就近运行路由控制器(即先匹配到的路由有效) |
[opts.host] | String / Regexp | 当前路由实例中,所有路由的匹配主机名 |
基础用法
const Koa = require('koa');
const Router = require('@koa/router');
const app = new Koa();
const router = new Router();
router.get('/', (ctx, next) => {
// ctx.router available
});
app.use(router.routes()).use(router.allowedMethods());
router.get|put|post|patch|delete|del ⇒ Router
创建router.verb()方法,verb是指HTTP请求方式(HTTP动词),比如router.get()
或 router.post()
。
使用router.verb()将URL与回调函数或控制器进行匹配。
另外,router.all()
可以用来匹配所有的请求方式(HTTP动词)。
router
.get('/', (ctx, next) => {
ctx.body = 'Hello World!';
})
.post('/users', (ctx, next) => {
// ...
})
.put('/users/:id', (ctx, next) => {
// ...
})
.del('/users/:id', (ctx, next) => {
// ...
})
.all('/users/:id', (ctx, next) => {
// ...
});
当路由被匹配时,其路径可通过ctx._matchedRoute
获取,如果是具名路由,可通过ctx._matchedRouteName
获取。
路由路径使用path-to-regexp转换为正则表达式。
在匹配请求时,查询字符串(URL Query)不被处理。
具名路由
可以给路由命名。在开发过程中,给路由命名会给到你一些帮助。
router.get('user', '/users/:id', (ctx, next) => {
// ...
});
router.url('user', 3);
// => "/users/3"
匹配主机
通过host
属性,路由可以匹配特定的主机。
const routerA = new Router({
host: 'hosta.com' // 仅匹配来自于`hosta.com`主机的请求
});
router.get('/', (ctx, next) => {
// Response for hosta.com
});
const routerB = new Router({
host: /^(.*\.)?hostb\.com$/ // 匹配hostb.com及其所有二级域名
});
router.get('/', (ctx, next) => {
// Response index for matched hosts
});
路由中间件
可以给路由添加中间件,可以是多个中间件:
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" }
}
);
参数 | 类型 | 描述 |
---|---|---|
path | String | 用来匹配的路由路径 |
[middleware] | function | 路由使用的中间件,可以是多个 |
callback | function | 路由控制器:路由匹配成功,执行的回调函数 |
嵌套路由
支持嵌套路由:
const forums = new Router();
const 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());
路由前缀
可以在路由器级别给路由路径设置前缀:
const router = new Router({
prefix: '/users'
});
router.get('/', ...); // responds to "/users"
router.get('/:id', ...); // responds to "/users/:id"
URL参数
路由参数被捕获并被添加到ctx.params
中。
类型:Router类实例的属性
router.get('/:category/:title', (ctx, next) => {
console.log(ctx.params);
// => { category: 'programming', title: 'how-to-node' }
});
path-to-regexp模块用于将路径转换为正则表达式。
router.routes ⇒ function
将路由器处理成中间件,它会分发一个请求的路由到该中间件以供匹配。
类型:Router类的实例的方法
router.use([path], middleware) ⇒ Router
当且仅当路由匹配时,使用给定的中间件。
中间件按照.use()
定义的顺序运行。它们是按顺序调用的,请求从第一个中间件开始,并沿着中间件堆栈“向下”运行。
类型:Router类实例的方法
参数 | 类型 |
---|---|
[path] | String |
middleware | function |
[…] | function |
// session中间件将会先于authorize运行
router
.use(session())
.use(authorize());
//仅在路由路径为/users才会运行userAuth中间件
router.use('/users', userAuth());
// 或者使用path数组:数组中有一个匹配成功就会运行userAuth中间件
router.use(['/users', '/admin'], userAuth());
app.use(router.routes());
router.prefix(prefix) ⇒ Router
为已经初始化的Router实例设置路径前缀。
类型:Router类实例的方法
参数 | 类型 |
---|---|
prefix | String |
例子:
const router = new Router({
prefix: '/categories'
});
router.get('/', ...); // respond "/categories"
router.prefix('/users');
router.get('/', ...); // responds to "/users"
router.get('/:id', ...); // responds to "/users/:id"
注意:prefix参数应该总是从 /
开始,否则它将不起作用。
router.allowedMethods([options]) ⇒ function
返回分离的中间件以响应OPTIONS请求,其中包含Allow Header的方法,以及响应405 Not allowed的方法和501 Not Implemented 的方法。
类型:Router类实例的方法
参数 | 类型 | 描述 |
---|---|---|
[options] | Object | |
[options.throw] | Boolean | 抛出错误来代替设置status和header |
[options.notImplemented] | function | 抛出返回值来代替默认的Not Implemented错误 |
[options.methodNotAllowed] | function | 抛出返回值来代替默认的Not allowed错误 |
例子
const Koa = require('koa');
const Router = require('@koa/router');
const app = new Koa();
const router = new Router();
app.use(router.routes());
app.use(router.allowedMethods());
关于 Boom的例子
const Koa = require('koa');
const Router = require('@koa/router');
const Boom = require('@hapi/boom');
const app = new Koa();
const router = new Router();
app.use(router.routes());
app.use(router.allowedMethods({
throw: true,
notImplemented: () => Boom.notImplemented(),
methodNotAllowed: () => Boom.methodNotAllowed()
}));
router.redirect(source, destination, [code]) ⇒ Router
用30X
状态码重定向源到目标URL。
源和目标URL都可以是路由名。
router.redirect('/login', 'sign-in');
其等价于
router.all('/login', ctx => {
ctx.redirect('/sign-in');
ctx.status = 301;
});
类型:Router类实例的方法
参数 | 类型 | 描述 |
---|---|---|
source | String | URL 或 路由名 |
destination | String | URL 或 路由名 |
[code] | Number | Http状态码(默认301) |
router.route(name) ⇒ Layer | false
查找名称为name的路由。
类型:Router类实例的方法
参数 | 类型 |
---|---|
name | String |
router.url(name, params, [options]) ⇒ String | Error
生成URL路由。接受一个路由名和路由参数。
类型:Router类实例的方法
参数 | 类型 | 描述 |
---|---|---|
name | String | 路由名 |
params | Object | 路由参数 |
[options] | Object | options参数 |
[options.query] | Object | String | query配置项 |
例子
router.get('user', '/users/:id', (ctx, next) => {
// ...
});
router.url('user', 3);
// => "/users/3"
router.url('user', { id: 3 });
// => "/users/3"
router.use((ctx, next) => {
// redirect to named route
ctx.redirect(ctx.router.url('sign-in'));
})
router.url('user', { id: 3 }, { query: { limit: 1 } });
// => "/users/3?limit=1"
router.url('user', { id: 3 }, { query: "limit=1" });
// => "/users/3?limit=1"
router.param(param, middleware) ⇒ Router
为指定的路由参数运行中间件。用于自动加载或验证。
类型:Router类实例的方法
参数 | 类型 |
---|---|
param | String |
middleware | function |
例子
router
.param('user', (id, ctx, next) => {
ctx.user = users[id];
if (!ctx.user) return ctx.status = 404;
return next();
})
.get('/users/:user', ctx => {
ctx.body = ctx.user;
})
.get('/users/:user/friends', 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
从URL映射(url pattern)和给定参数生成URL。此方法在将参数包含在URL中之前对参数进行URL编码。
类型:Router类的静态方法
参数 | 类型 | 描述 |
---|---|---|
path | String | url映射(url pattern) |
params | Object | url参数 |
例子
const url = Router.url('/users/:id', {id: 1});
// => "/users/1"