创建 Koa 应用

  1. 利用 http 模块 创建(http 融合的方式,有的需求使用 http 更方便一点)

    const Koa = require("koa");
    const app = new Koa();
    const http = require("http");
    const server = http.createServer(app.callback());
    
    server.listen(port, callback);
    
  2. 直接创建 Koa 实例

    const Koa = require("koa");
    const app = new Koa();
    
    app.listen(port, callback);
    

注册中间件

// 中间件的函数格式
function middleware1(ctx, next){
  // ctx 上下文对象
  // next 移交给下一个中间件的函数
}

// 注册中间件
app.use(middleware1);

中间件原理

中间件执行顺序

  1. 示例代码 1

    const Koa = require('koa');
    const app = new Koa();
    
    app.use(async (ctx, next) => {
        console.log(1);
        next(); // 调用 next 表示执行下一个中间件 
        console.log(2);
    })
    app.use(async (ctx, next) => {
        console.log(3);
        next();
        console.log(4)
    })
    app.use(async (ctx, next) => {
        console.log(5)
        next();
        console.log(6)
    });
    app.listen(4000);
    // 输出:
    // 1
    // 3
    // 5
    // 6
    // 4
    // 2
    
  2. 示例代码 2

    const Koa = require('koa');
    const app = new Koa();
    
    const log = () => {
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                console.log('logger');
                resolve()
            }, 3000);
        })
    }
    app.use(async (ctx, next) => {
        console.log(1);
        next(); // 调用 next 表示执行下一个中间件 
        console.log(2);
    })
    app.use(async (ctx, next) => {
        console.log(3);
        await log(); // -- 等待
        next();
        console.log(4)
    })
    app.use(async (ctx, next) => {
        console.log(5)
        next();
        console.log(6)
    });
    app.listen(4000);
    // 输出:
    // 1
    // 3
    // 2
    // logger
    // 5
    // 6
    // 4
    
  3. 示例代码 3

    const Koa = require('koa');
    const app = new Koa();
    
    const log = () => {
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                console.log('logger');
                resolve()
            }, 3000);
        })
    }
    app.use(async (ctx, next) => { // fn1
        console.log(1);
        await next();
        console.log(2);
        ctx.body = 'hello 1'; // 会取第一个中间件执行完的结果(执行顺序在最后)
    })
    app.use(async (ctx, next) => {
        console.log(3);
        await log(); // -- 等待
        ctx.body = 'hello 2'
        next();
        console.log(4)
    })
    app.use(async (ctx, next) => {
        console.log(5)
        ctx.body = 'hello 3';
        next();
        console.log(6)
    });
    app.listen(3000);
    // 界面响应: hello 1
    

context

  1. context 中包含 4 个重要对象:

    • reqhttp 模块内置对象;
    • reshttp 模块内置对象;
    • requestkoa 封装的请求对象,用于获取请求传递的信息;
    • responsekoa 封装的响应对象,用户设置响应信息;
  2. Koa 不建议使用原生的对象,绝大部分情况下,都应该使用它封装的对象;

  1. context 实现了不同应用以及不同请求之间的环境隔离

  2. ctx 实现代理

响应流程

当给 body 赋值时, Koa 会将 status 自动赋值为 200204

简化 api

为了方便使用, Koarequestresponse 中的很多成员提取到了 context 中,并使用访问器控制

Koa 中的加密是利用第三方库 KeyGrip 完成的,该库使用多个秘钥,轮流用它们加密目标字符串,在解密时,选择合适的秘钥进行解密;

这种叫做旋转加密的方式,更加难以破解;

  1. Koa 原生支持 cookie ,不需要安装其他中间件

    ctx.cookies.set(name, value, [options]); // 设置cookie
    ctx.cookies.get(name); // 获取cookie
    
  2. Koa 同样支持加密的 cookie

    app.keys = ['im a newer secret', 'i like turtle']; // 加密的多个秘钥
    ctx.cookies.set(name, value, { signed: true}); // 设置加密的cookie
    ctx.cookies.get(name, {signed: true}); // 解密cookie
    

自定义空间

  1. 有时,某些中间件希望添加一些额外的信息,以方便后续中间件处理,比如当前登录的用户信息;

  2. Koa 建议把这些信息添加到 ctx.state 中,该属性默认是一个空对象,专门提供给中间件开发者添加额外信息的;

错误处理

利用中间件进行错误处理

  1. 为了方便处理错误,最好使用 try…catch 将其捕获;

  2. 但是,为每个中间件都写 try…catch 太麻烦,可以让最外层的中间件,负责所有中间件的错误处理;

const Koa = require('koa')
const fs = require('fs')
const { promisify } = require('util')
const readFile = promisify(fs.readFile)
const app = new Koa()

// 在最外层添加异常捕获的中间件
app.use(async (ctx, next) => {
  try {
    await next()
  } catch (err) {
    ctx.status = 500
    ctx.body = err.message
    ctx.app.emit('error', err, ctx)
    // ctx.body = '服务端内部错误'
  }
})

app.use(async (ctx, next) => {
  // next() // 无法捕获后面的异步中间件

  // return next() // 可以捕获异步错误
  await next() // 可以捕获异步错误
})

app.use(async ctx => {
  // 没有这个文件,会报错
  const data = await readFile('./dnskjandsa.html')
  ctx.type = 'html'
  ctx.body = data
})

app.listen(3000, () => { console.log('http://localhost:3000') })

利用 EventEmitter 事件监听进行错误处理

  1. 由于 Koa 实现了 EventEmitter ,除了错误处理之外,还可以利用它做别的事情

  2. Koa 实现了 EventEmitter ,因此,它是通过注册事件的方式处理错误的

const Koa = require('koa')
const fs = require('fs')
const { promisify } = require('util')
const readFile = promisify(fs.readFile)
const app = new Koa()

app.use(async ctx => {
  // 没有这个文件,会报错
  const data = await readFile('./dnskjandsa.html')
  ctx.type = 'html'
  ctx.body = data
})

app.on('error', err => { console.log('app error', err) })

app.listen(3000, () => { console.log('http://localhost:3000') })

释放 error 事件

  1. 需要注意的是,如果错误被 try…catch 捕获,就不会触发 error 事件;

  2. 这时,必须调用 ctx.app.emit(),手动释放 error 事件,才能让监听函数生效;

const Koa = require('koa')
const fs = require('fs')
const { promisify } = require('util')
const readFile = promisify(fs.readFile)
const app = new Koa()

// 在最外层添加异常捕获的中间件
app.use(async (ctx, next) => {
  try {
    await next()
  } catch (err) {
    ctx.status = 500
    ctx.body = err.message
    ctx.app.emit('error', err, ctx)
  }
})

app.use(async ctx => {
  // 没有这个文件,会报错
  const data = await readFile('./dnskjandsa.html')
  ctx.type = 'html'
  ctx.body = data
})

app.on('error', err => { console.log('app error', err) })

app.listen(3000, () => { console.log('http://localhost:3000') })
打赏作者
您的打赏是我前进的动力
微信
支付宝
评论

中午好👏🏻,我是 ✍🏻   疯狂 codding 中...

粽子

这有关于前端开发的技术文档和你分享。

相信你可以在这里找到对你有用的知识和教程。

了解更多

目录

  1. 1. 创建 Koa 应用
  2. 2. 注册中间件
    1. 2.1. 中间件原理
    2. 2.2. 中间件执行顺序
  3. 3. context
    1. 3.1. 响应流程
    2. 3.2. 简化 api
    3. 3.3. cookie
    4. 3.4. 自定义空间
    5. 3.5. 错误处理
      1. 3.5.1. 利用中间件进行错误处理
      2. 3.5.2. 利用 EventEmitter 事件监听进行错误处理
      3. 3.5.3. 释放 error 事件