Koa的历史

  • Express
    • 2010.6 TJ开始编写Express
    • 2014发展到v0.12,基本成熟,移交StrongLoop
  • Koa
    • 2013.8 TJ开始编写Koa
    • 2015.8 Koa发布v1.0.0版本
  • Node.js
    • 2013.3 Node.js v0.10发布
    • 2014.12 io.js不满Node.js的管理发起分裂
    • 2015.2 Node.js v0.12发布
    • 2015.9 Node.js与io.js合并为node.js v4.0
  • Koa开始对Node.js的支持

    • 2015.2 Koa放弃对Node v0.11以下的支持,并开始支持io.js
    • 2015.10 Koa放弃对Node v4.0以下的支持,并用ES6重写的所有代码,发布v2.0.0内测版

      Koa对比Express

  • 编程模型不同

    • Express的中间件是线性的
    • Koa的中间件是U型的
  • 对语言特性的使用不同
    • Express使用回调函数 next()
    • Koa v1.x 使用generator语法
    • Koa v2.x 使用async/await语法
  • 2011-2016大概率会用Express
  • 2017以后 会使用Koa

    Koa的中间件模型

    U型或洋葱模型
    image.png
    $ yarn add koa
    $ yarn add --dev @types/koa
    $ tsc --init
    $ ts-node-dev server.ts

server.ts

  1. import Koa from 'koa'
  2. const app = new Koa()
  3. app.use(async (ctx, next) => {
  4. ctx.body = 'hello'
  5. await next()
  6. ctx.body += ' haha'
  7. })
  8. app.use(async (ctx, next) => {
  9. ctx.body += ' world'
  10. await next()
  11. })
  12. app.use(async (ctx, next) => {
  13. ctx.set('Content-Type', 'text/html;charset=utf-8')
  14. await next()
  15. })
  16. app.listen(3000)

中间件代码

  1. import Koa from 'koa'
  2. const app = new Koa()
  3. app.use(async (ctx, next) => {
  4. await next();
  5. const time = ctx.response.get('X-Response-Time');//读取 response header
  6. console.log(`${ctx.url} - ${time}`);
  7. });
  8. app.use(async (ctx, next) => {
  9. const start = Date.now();//记录开始时间
  10. await next();
  11. const time = Date.now() - start;//记录结束时间 -start=总耗时
  12. ctx.set('X-Response-Time', `${time}ms`);//写到response header里
  13. });
  14. app.use(async ctx => {
  15. ctx.body = 'Hello World';
  16. // 最后一个中间件可以不写 await next()
  17. });
  18. app.listen(3000)

image.png

await next()释义

  1. app.use(async (ctx, next) => {
  2. const start = Date.now();
  3. await next(); // ()等待 下一个中间件
  4. const time = Date.now() - start;
  5. ctx.set('X-Response-Time', `${time}ms`);
  6. });
  • next()表示进入下一个函数
  • 下一个函数会返回一个Promise对象,称为p
  • 下一个函数所有代码执行完毕后,将p置为成功
  • await会等待p成功后,再回头执行剩余的代码

    awiat next()改写

    Promise写法

    1. app.use(async (ctx, next) => {
    2. const start = Date.now();
    3. return next().then(()=>{
    4. const time = Date.now() - start;
    5. ctx.set('X-Response-Time', `${time}ms`);
    6. });
    7. });
  • 一定要写return,因为中间件必返回Promise对象

  • 错误处理在这里有点反模式,用app.on(‘error’)更方便一点

Express如何实现Response Time

  1. const express = require('express')
  2. const app = express()
  3. app.use((req, res, next) => {
  4. const start = new Date()
  5. res.locals.start = start
  6. next()
  7. })
  8. app.use((req, res, next) => {
  9. res.write('hello world')
  10. res.end()
  11. next()
  12. })
  13. app.use((req, res, next) => {
  14. const time = new Date().valueOf() - res.locals.start
  15. console.log('time-', time)
  16. })
  17. app.listen(3000)
  • 使用response-time库 ```javascript const express = require(‘express’) const responseTime = require(‘response-time’) const app = express()

app.use(responseTime()) app.use((req, res, next) => { res.write(‘hello world’) res.end() next() }) app.use((req, res, next) => { console.log(res.get(‘x-response-time’)) next() }) app.listen(3000, () => { console.log(‘3000’) }) ```

Koa API

app.xxx

app.env app.proxy app.subdomainOffset app.listen() app.callback() app.use(fn) 插入中间件fn app.keys app.context app.on(‘error’,fn) 错误处理 app.emit 触发事件

ctx.xxx

ctx.req Node.js封装的请求 ctx.res ctx.request Koa封装的请求 ctx.response
ctx.state 跨中间件分享数据 ctx.app ctx.cookies.get/set ctx.throw ctx.assert ctx.respond Request委托 Response委托

ctx.request.xxx

request.header request.headers request.method request.length request.url request.origin request.href request.path request.querystring request.search request.host request.hostname request.URL request.type request.charset request.query request.fresh request.stale request.protocol … request.idempotent request.get(field)

ctx.response.xxx

response.header response.headers response.socket response.status response.message response.length response.body x5 response.get() response.set() x2 response.append() response.type response.is() response.redirect(url,[alt]) response.attachment() response.headerSent response.flushHeaders() …

谁在用Koa

egg.js

更推荐
Next.js/Nuxt/Nest