开启一个本地服务器
// 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)
得到的效果如下
异步处理和中间件(middleware)
在koa2.0中使用async await 实现异步处理
官网中对上述基本使用的中间件做出以下解释
下面以 “Hello World” 的响应作为示例,当请求开始时首先请求流通过
x-response-time和logging中间件,然后继续移交控制给response中间件。当一个中间件调用next()则该函数暂停并将控制传递给定义的下一个中间件。当在下游没有更多的中间件执行后,堆栈将展开并且每个中间件恢复执行其上游行为。
也就是说,对于每一个http请求koa会调用app.use中的async函数,先执行next()前面的语句,然后执行完下一个app.use()之后再来执行next()后面的语句
修改前面实例,执行得出输出结果
// 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获取传递的参数