浅析Koa2 基础内容-中间件(二)

564 阅读2分钟

1 koa应用可以使用一下几种中间件

1 应用级中间件
2 路由级中间件
3 错误处理中间件
4 第三方中间件

应用级中间件

egg: 有如下需求 《匹配路由之前在终端打印日期》

话不多说,上代码

const Koa = require('koa')
const Router = require('koa-router')
const app = new Koa()
const router = new Router()

// 匹配路由之前打印日期
app.use(async(ctx, next) => {
  console.log(new Date())
  next()
})
router.get('/', (ctx) => {
  ctx.body = '首页'
})
router.get('/news', (ctx) => {
  ctx.body = '新闻页'
})

app.use(router.routes())
app.use(router.allowedMethods())
app.listen(8032)

匹配到路由/, /new,以及其他未定义的路由之前都会执行app.use中间件方法,打印当前时间戳,然后执行next下一个中间件

路由级中间件

匹配任何路由 如果不写next,这个路由被匹配到了就不会继续向下匹配

const router = new Router()

router.get('/', (ctx) => {
  ctx.body = '首页'
})
router.get('/news', async (ctx, next) => {
  ctx.body = '新闻页1'
  await next()
})
router.get('/news', (ctx) => {
  ctx.body = '新闻页2'
})

app.use(router.routes())
app.use(router.allowedMethods())
app.listen(8032)

匹配到/news 页面输出‘新闻页2’ why?

匹配到/news路由之后 执行await 下一个中间件,再次匹配到/news 页面对应输出新闻页2

如果我们去掉第二个news路由,页面对应输出‘新闻页1’
如果我们修改第二个news路由 
router.get('/list', (ctx) => {
  ctx.body = '列表'
}) 
页面对应还是输出‘新闻页1’

错误处理中间件

egg: 有如下需求

匹配首页路由输出 首页 打印当前路由

匹配/news 输出 新闻页 打印当前路由

其他路由 输出 404页面

const Koa = require('koa')
const Router = require('koa-router')
const app = new Koa()
const router = new Router()

app.use(async (ctx, next) => {
  console.log('我是中间件')
  next()
  if (ctx.status === 404) {
    ctx.status = 404
    ctx.body = '404页面'
  } else {
    console.log(ctx.url)
  }
})

router.get('/', (ctx) => {
  ctx.body = '首页'
})
router.get('/news', async (ctx, next) => {
  ctx.body = '新闻页'
})

app.use(router.routes())
app.use(router.allowedMethods())
app.listen(8032)

第三方中间件

常用的第三方中间页有路由 静态资源 body-parser等,具体内容参考浅析Koa2 基础内容(一)

2 koa中间件执行顺序

洋葱圈模型

const Koa = require('koa')
const Router = require('koa-router')
const app = new Koa()
const router = new Router()

app.use(async (ctx, next) => {
  console.log(1)
  await next()
  console.log(2)
})
app.use(async (ctx, next) => {
  console.log(3)
  await next()
  console.log(4)
})
app.use(async (ctx, next) => {
  console.log(5)
  await next()
  console.log(6)
})

router.get('/', (ctx) => {
  ctx.body = '首页'
})
router.get('/news', async (ctx, next) => {
  ctx.body = '新闻页'
})

app.use(router.routes())
app.use(router.allowedMethods())
app.listen(8032)

执行顺序 1 3 5 6 4 2

中间件方法都为同步时 next()前面的await可以省略不写。为异步时需要加上

const Koa = require('koa')
const Router = require('koa-router')
const app = new Koa()
const router = new Router()

// 匹配任何路由 如果不写next,这个路由被匹配到了就不会继续向下匹配
app.use(async (ctx, next) => {
  console.log(1)
  await next()
  console.log(2)
})
app.use(async (ctx, next) => {
  await next()
  return new Promise((resolve,reject) => {
    setTimeout(() => {
      console.log('3')
      resolve('44')
    }, 1000)
  })
})
app.use(async (ctx, next) => {
  console.log(4)
  await next()
  console.log(5)
})

router.get('/', (ctx) => {
  ctx.body = '首页'
})
router.get('/news', async (ctx, next) => {
  ctx.body = '新闻页'
})

app.use(router.routes())
app.use(router.allowedMethods())
app.listen(8032)

页面输出1 4 5 3 2