Koa 路由中间件原理及使用技巧
发布于 4 年前 作者 zhb333 4069 次浏览 来自 分享

本文主要是为了介绍路由的作用,以及在 Koa 路由中间件的使用,一些高级用法,和实用技巧等

什么是路由?

  • 处理不同的 URL
  • 处理不同的 HTTP 方法 (GETPOSTPUTDELETEPATCHOPTIONS)
  • 解析 URL 上的参数

HTTP 协议而言,路由可以理解为,根据不同的 HTTP 请求,返回不同的响应;

如果没有路由会怎么样?请看下面的代码:

const Koa = require('koa')
const app = new Koa()

app.use(async ctx => {
  ctx.body = 'hello world'
})

app.listen(3000)

通过 Postman 访问 3000 端口,无论是何种 HTTP 方法,还是不同的 URL 都将返回相同的内容

这种没有路由WEB服务,几乎做不了什么有价值的事情

自定义 Koa 路由中间件

路由,最基本的功能就是可以处理不同的URL, 不同的 HTTP方法, 以及解析 URL 参数

处理不同的 HTTP 方法

const Koa = require('koa')
const app = new Koa()

app.use(async ctx => {
  if (ctx.method === 'GET') {
    ctx.body = 'GET 请求'
  } else if (ctx.method === 'POST') {
    ctx.body = 'POST 请求'
  } else if (ctx.method === 'PUT') {
    ctx.body = 'PUT 请求'
  } else if (ctx.method === 'DELETE') {
    ctx.body = 'DELETE 请求'
  }
})

app.listen(3000)

处理不同的 URL

app.use(async ctx => {
  if (ctx.method === 'GET') {
    switch (ctx.url) {
      case '/': ctx.body = '首页'; break;
      case '/users': ctx.body = '用户列表'; break;
      case '/articles': ctx.body = '文章列表'; break;
      default: ctx.status = 404
    }
  }
})

解析 URL 参数

app.use(async ctx => {
  if (ctx.method === 'GET') {
    // 根据用户 ID 获取用户信息
    if (/^\/users\/(\w+)$/.test(ctx.url)) {
      return ctx.body = `用户 ID 为: ${RegExp.$1}`
    }
    ctx.status = 404
  }
})

上面的演示代码只是最最基本的路由概念,完整的路由逻辑实际需要考虑的情况更加复杂

建议

一个优秀、优雅的程序,需要独立维护的代码越少越好,千万不要干重复造轮子的事情,生命有限!使用官方的中间件,或者其它第三方优秀的中间件,可以节省开发时间,提高开发效率!

koa-router

koa-router 的基本使用

安装

yarn add koa-router

基本使用

const Koa = require('koa');
const Router = require('koa-router');

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

// 处理不同的 HTTP 方法
router
  .get('/users', ctx => {
    ctx.body = '获取用户列表'
  })
  .post('/users', ctx => {
    ctx.body = '创建用户'
  })
  .put('/users/:id', ctx => {
    // 解析 URL 参数
    ctx.body = `更新 ID 为 ${ctx.params.id} 的用户`
  })
  .delete('/users/:id', ctx => {
    // 解析 URL 参数
    ctx.body = `删除 ID 为 ${ctx.params.id} 的用户`
  })

// 注册路由中间件
app.use(router.routes())

app.listen(3000)

路由前缀

配置 koa-router 的路由前缀,实现路由分类

const Koa = require('koa');
const Router = require('koa-router');

const app = new Koa();

const articleRouter = new Router({ prefix: '/articles' }) // 文章接口
const userRouter = new Router({ prefix: '/users' }) // 用户接口

articleRouter.get('/', ctx => ctx.body = '文章列表')
userRouter.get('/', ctx => ctx.body = '用户列表')

app.use(articleRouter.routes())
app.use(userRouter.routes())

app.listen(3000)

使用 koa-routerallowedMethods 方法, 可以实现 HTTPOPTIONS方法请求

OPTIONS 请求可以检测接口所支持的请求方法

假如有如下代码,通过 userRouter.allowedMethods() 中间件,让 /users 接口实现 options 方法

const Koa = require('koa');
const Router = require('koa-router');

const app = new Koa();

const userRouter = new Router({ prefix: '/users' }) // 用户接口

userRouter.get('/', ctx => ctx.body = '用户列表')
userRouter.post('/', ctx => ctx.body = '创建用户')
userRouter.put('/:id', ctx => ctx.body = ctx.params.id)

// 使用了 userRouter.allowedMethods() 中间件,让 /users 接口实现 options 方法
app.use(userRouter.routes()).use(userRouter.allowedMethods())

app.listen(3000)

使用 postman 测试 OPOTIONS 方法

2020-03-23_013731.jpg

响应头信息中的 ALLOW 字段中,显示了 /users 接口支持的 HTTP 方法有 GETPOSTPUT

如果 OPTIONS 方法请求接口没有实现的 HTTP 方法,将会返回 405 的状态码

2020-03-23_014618.jpg

如果 OPTIONS 方法请求 HTTP 不支持的方法,将会返回 501 的状态码

2020-03-23_014835.jpg

koa 多路由注册的技巧

在实际的项目中,我们的接口是多种多样的,不可能在入口文件中定义全部路由

创建 routes 文件夹,存放所有不同的路由接口

├── routes (路由)
│ └── articles.js
│ └── users.js
│ └── index.js

├── index.js (入口)

└── package.json

// routes/articles.js  

const Router = require('koa-router')
const router = new Router({ prefix: '/articles' })

router.get('/', ctx => ctx.body = '文章列表')

module.exports = router
// routes/users.js  

const Router = require('koa-router')
const router = new Router({ prefix: '/users' })

router.get('/', ctx => ctx.body = '文章列表')

module.exports = router
// routes/index.js  

const fs = require('fs');
module.exports = (app) => {
  // 使用 fs 模块自动读取并注册 routes 文件夹下所有路由接口
  fs.readdirSync(__dirname).forEach(file => {
    if (file === 'index.js') { return; }
    const route = require(`./${file}`);
    app.use(route.routes()).use(route.allowedMethods());
  });
}
const Koa = require('koa');
const app = new Koa();
const routing = require('./routes');

// 一次性注册路由
routing(app)

app.listen(3000)
2 回复

对比着https://github.com/delvedor/find-my-way讲会更好。

另外对koa-router源码,核心模块也可以补充一下

@i5ting 嗯嗯,感谢您的建议~ 我会研究一下的

回到顶部