## 一、中间件
### 1.1 logger功能
> Koa 的最大特色,也是最重要的一个设计,就是中间件(middleware)。
> Logger:打印日志
```
const Koa = require('koa')
const app = new Koa()
const main = ctx => {
console.log(`${Date.now()} ${ctx.request.method} ${ctx.request.url}`)
ctx.response.body='请求了'
}
app.use(main)
app.listen(3000)
# 访问后
1502144902843 GET /
```
### 1.2 中间件概念
> 上面例子里的Logger功能,可以拆分成一个独立函数
```
const Koa = require('koa')
const app = new Koa()
const logger = (ctx,next) => {
console.log(`${Date.now()} ${ctx.request.method} ${ctx.request.url}`)
next()
}
const main = ctx => {
ctx.response.body='呵呵'
}
app.use(logger)
app.use(main)
app.listen(3000)
```
- 以上的logger函数,main函数就是一个中间件middleware,因为它处在http request和response之间,用来实现某种中间功能
- app.use(middleWare) 来使用中间件
- 参数:默认接受2个参数 (ctx,next),ctx为context对象,当执行完中间件的功能后,调用next()将执行权交移给下一个中间件
### 1.3 中间件栈
>多个中间件会形成一个栈结构(middle stack),以"先进后出"(first-in-last-out)的顺序执行。
>
1. 最外层的中间件首先执行。
2. 调用next函数,把执行权交给下一个中间件。
3. ...
4. 最内层的中间件最后执行。
5. 执行结束后,把执行权交回上一层的中间件。
6. ...
7. 最外层的中间件收回执行权之后,执行next函数后面的代码。
```
const one = (ctx,next) => {
console.log('one->')
next()
console.log('<-one')
}
const two = (ctx, next) => {
console.log('2->')
next()
console.log('<-2')
}
# 执行结果
one->
2->
<-2
<-one
```
- 如果不调用next(),则不会移交执行权
### 1.4 异步中间件
> 如果有异步操作(比如读取数据库),中间件就必须写成 async 函数。
```
//fs.promised模块是对fs模块的扩展,需单独这安装后使用
const fs = require('fs.promised');
const Koa = require('koa');
const app = new Koa()
const main = async function(ctx,next){
ctx.response.type='html';
ctx.response.body= await fs.readFile('./template.html','utf8')
}
app.use(main)
app.listen(3000)
```
> **fs.promised模块**:
> 原fs模块读取文件后都要用回调函数来处理结果,而fs.promised可以用**promised**来代替回调函数。
```
# 安装
npm i fs.promised -S
# 使用
const fs = require('fs.promised')
fs.readFile('./test.json').then(v=>console.log(v),error=>console.log(error))
```
### 1.5 中间件的合成
> koa-compose模块可以将多个中间件合成为一个
```
const Koa = require('koa')
const compose = require('koa-compose')
const app = new Koa()
const logger = function (ctx,next) {
console.log(`${Date.now()} ${ctx.request.method} ${ctx.request.url}`)
next()
}
const main = function (ctx,next) {
ctx.response.body='这是首页'
}
const middleWare = compose([logger, main])
app.use(middleWare)
app.listen(3000)
```