Koa 的基本使用

133 阅读3分钟

开启一个本地服务器

// hello world 

import Koa from 'koa';
const app = new Koa();

// logger

app.use(async (ctx, next) => {
  await next();
  const rt = ctx.response.get('X-Response-Time');
  console.log(`${ctx.method} ${ctx.url} - ${rt}`);
});

// x-response-time

app.use(async (ctx, next) => {
  const start = Date.now();
  await next();
  const ms = Date.now() - start;
  ctx.set('X-Response-Time', `${ms}ms`);
});

// response
app.use(async ctx => {
  ctx.body = 'Hello World';
});

app.listen(3000)

得到的效果如下

终端显示.png

image.png

异步处理和中间件(middleware)

在koa2.0中使用async await 实现异步处理

官网中对上述基本使用的中间件做出以下解释

下面以 “Hello World” 的响应作为示例,当请求开始时首先请求流通过 x-response-time 和 logging 中间件,然后继续移交控制给 response 中间件。当一个中间件调用 next() 则该函数暂停并将控制传递给定义的下一个中间件。当在下游没有更多的中间件执行后,堆栈将展开并且每个中间件恢复执行其上游行为。

也就是说,对于每一个http请求koa会调用app.use中的async函数,先执行next()前面的语句,然后执行完下一个app.use()之后再来执行next()后面的语句

image.png

修改前面实例,执行得出输出结果

// logger

app.use(async (ctx, next) => {
  console.log('logger1')
  await next();
  console.log('logger2')
});

// x-response-time
app.use(async (ctx, next) => {
  console.log('x-response-time1')
  await next();
  console.log('x-response-time2')
});

// response
app.use(async ctx => {
  console.log('response')
  ctx.body = 'Hello World';
});

结果如下

logger1
x-response-time1
response
x-response-time2
logger2
logger1
x-response-time1
response
x-response-time2
logger2

这个异步处理其实就是 async和await ,next()表示执行下一个app.use()。我们把每个async函数称之为中间件

这里会执行两次的原因在于,我是使用浏览器刷新来发送请求,浏览器会默认请求一次favicon.ico ,使用接口工具调用一下,终端就只打印一次。

ctx 和 next

了解完执行顺序,来看一下这两个参数ctx和next

在终端打印一下这两个参数

//ctx 
{
  request: {
    method: 'GET',
    url: '/',
    header: {
      host: 'localhost:3000',
      connection: 'keep-alive',
      'sec-ch-ua': '"Google Chrome";v="105", "Not)A;Brand";v="8", "Chromium";v="105"',
      'sec-ch-ua-mobile': '?0',
      'sec-ch-ua-platform': '"Windows"',
      'upgrade-insecure-requests': '1',
      'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36',
      accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
      'sec-fetch-site': 'none',
      'sec-fetch-mode': 'navigate',
      'sec-fetch-user': '?1',
      'sec-fetch-dest': 'document',
      'accept-encoding': 'gzip, deflate, br',
      'accept-language': 'zh-CN,zh;q=0.9'
    }
  },
  response: {
    status: 200,
    message: 'OK',
    header: [Object: null prototype] {
      'content-type': 'text/plain; charset=utf-8',
      'content-length': '11',
      'x-response-time': '3ms'
    }
  },
  app: { subdomainOffset: 2, proxy: false, env: 'development' },
  originalUrl: '/',
  req: '<original node req>',
  res: '<original node res>',
  socket: '<original node socket>'
}

打印next得到:[Function: bound dispatch]

ctx 是维护的一个对象,是requst 和response的集合 在使用中间件时,回调函数(中间件)可以直接获取到这个对象

//通过闭包实现 ctx传递过程

app.use = (fun)=>{
let ctx = {response,request}
return fun(ctx)

koa router

通过router进行接口管理

//router.js
const router = require('koa-router')() // 实例化一个路由
// 配置接口
router.get('/',async ctx=>{
ctx.body = '' // 接口返回的内容
})
router.post('/post', async ctx=>{
...
})

// 嵌套子路由
cosnt sonRouter = require('./son.js')
router.use('/path',sonRouter.routes(),sonRuter.allowedMethods())
\\ app.js

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

koa获取请求参数

调接口经常需要传递参数,看一下如何获取get和post 请求的参数

  • get ctx.query
  • post 使用中间件koa-bodyparser 就可以通过 ctx.request.body获取传递的参数