Skip to content

Latest commit

 

History

History
244 lines (189 loc) · 6.2 KB

learn koa2--router.md

File metadata and controls

244 lines (189 loc) · 6.2 KB

Table of Contents generated with DocToc

learn koa2--router

给Koa2增加路由功能

鉴于Koa的轻量级设计,其自身并没有提供route的功能,而需要我们自己去安装koa-router组件:

# 针对Koa2
$ npm install koa-router@next --save
// app/app.js
import Koa from 'koa';
import koaRouter from 'koa-router';
const app = new Koa();
const router = koaRouter();

router.get('/about', (ctx, next) => {
    ctx.body = "this is the about page";
});

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

app.listen(7000);

export default app;

然后正常启动项目,进入localhost:7000/about,就能看见也页面上加载的this is the about page了。

koa-router的更多使用方法,可以参考官方文档

当路由增多的时候,我们不可能把它们全部放在app.js这个文件中,而是应该新建一个router.js文件或者routes文件夹。我更推荐使用文件夹的形式,那样的话,不同的路由可以根据各个文件来进行分类,更加便于管理:

- app
    - routes
        home.js
        articles.js
        # ...
        index.js

编写home.js

// app/routes/home.js
import koaRouter from 'koa-router';

const router = koaRouter({
  prefix: '/'
});
router.get('about', (ctx, next) => {
  ctx.body = 'about page';
});

module.exports = router;

解释下prefix

路由的前缀。在这个文件里使用的router,在生成时带有参数{prefix: '/'},说明该文件里定义的路由都必须是以/开头的,例如说//about/articles等。因为一个文件里只定义一个prefix,所以便于之后进行管理。

而对于articles.js

// app/routes/articles.js
import koaRouter from 'koa-router';

const router = koaRouter({
  prefix: '/articles'
});
// 路由/articles必须定义在含有{prefix: '/articles'}的路由文件里

router.get('/:id/author', (ctx, next) => {
  ctx.body = 'article author page';
});
router.get('/:id/info', (ctx, next) => {
  ctx.body = 'article info page';
});
// 要注意的是,需要把/路由,也就是/articles路由放在最后
// 因为路由是个中间件,会从上到下取第一个匹配的。
// 如果/articles在上面的话,则/:id/info会正常匹配,但/:id/info/会匹配到/articles
router.get('/', (ctx, next) => {
  ctx.body = 'articles page';
});

module.exports = router;

上面文件里定义的路由有:

  • /articles
  • /articles/
  • /articles/:id/author
  • /articles/:id/info

此时进入localhost:7000/articles页面,可以看见articles page,并且进入类似localhost:7000/articles/1/author这样的页面则也能获取到对应的article author page

最后,来看一下如何在index.js便捷的获取到所有路由:

// app/routes/index.js
import fs from 'fs';
import path from 'path';
import koaRouter from 'koa-router';
const router = koaRouter();

fs
  .readdirSync(__dirname)
  .filter(file =>
    (file.indexOf('.') !== 0) && (file.split('.').slice(-1)[0] === 'js') && file !== 'index.js'
  )
  .forEach(file => {
    console.log(file);
    const route = require(path.join(__dirname, file));
    router.use(route.routes(), route.allowedMethods());
  });

// 把根路由/放在最后,以免当其他路由后面带有/时匹配到根路由
router.get('/', (ctx, next) => {
  ctx.body = 'home page';
});

export default router;

扩展:koa-router的使用

基本使用

// 基本使用
import Koa from 'koa';
import koaRouter from 'koa-router';

const router = koaRouter();
const app = new Koa();

router.get('/', (ctx, next) => {
  // ...
});

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

路由的get|put|post|patch|delete方法

// 直接通过router.xxx方法即可,可以线性链接各方法
router
  .get('/', (ctx, next) => {
    ctx.body = 'Hello Koa';
  })
  .post('/users', (ctx, next) => {
    // ...
  })
  .put('/users/:id', (ctx, next) => {
    // ...
  })
  .del('/users/:id', (ctx, next) => {
    // ...
  });

动态路由

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

使用middleware

router.get(
  '/users/:id',
  (ctx, next) => {
    return User.findOne(ctx.params.id).then((user) => {
      ctx.user = user;
      return next();
    });
  },
  (ctx) => {
    console.log(ctx.user);
    // => { id: 17, name: "Alex" }
  }
);

路由嵌套

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());

// 相当于posts接收的`/`和`/:pid`都嵌套到forums内
// 这样处理之后,app可以相应类似"/forums/123/posts"或者"/forums/123/posts/123"
app.use(forums.routes());

指定前缀

var router = new Router({
  prefix: '/users'
});

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