Node框架:Koa 和 Express

1. express

基于node.js平台的极简灵活的web应用框架,基于Connect中间件,自身封装了路由,视图处理等功能。

2. koa

web应用框架,由express幕后原班人马打造,致力于成为web应用和api开发领域中更小更富有表现力更健壮的基石。框架自身不包含任何中间件,很多功能借助第三方中间件。基于es7的async解决回调地狱和麻烦处理问题,受到开发者欢迎。

3. 不同点:
以下介绍部分Koa和Express不同点,以例子说明:

  • 路由处理Express是自身集成的,Koa需要引入中间件。(同理视图功能是express内置的模块,Koa则是需要Koa-views中间件)

    const express = require('express')
    const app = express()
    
    app.get('/', function (req, res) {
      res.send('Hello Express')
    })
    
    app.listen(3000)
    
    // Koa
    const Koa = require('koa')
    const route = require('koa-route')
    
    const app = new Koa()
    
    app.use(route.get('/', async (ctx) => {
      ctx.body = 'Hello Koa'
    }))
    
    app.listen(3000)
    
  • Context
    Koa 新增了一个 Context 对象,用来代替 Express 中的 Request 和 Response,作为请求的上下文对象。
    Context 上除了 Request 和 Response 两个对象之外,还有 Node.js 原生提供的 req 、res、socket 等对象。

  • express生命周期不确定/koa确定
    看两个例子:

    var express = require('express');
    var app = express();
    
    app.use((req, res, next) => {
      console.log(1); // 1
      next(); // 2
      console.log(2); // 5
    });
    
    app.use((req, res, next) => {
      console.log(3); // 3
      new Promise((resolve => { // 4
        setTimeout(resolve, 300);
      })).then(() => {
        next(); // 6
        console.log(4); // 8
      });
    });
    
    app.use(function(req, res) {// 7
      res.send('Hello World');
    })
    
    app.listen(3000)
    

    输出:1 3 2 4

    const Koa = require('koa');
    const app = new Koa();
    
    app.use(async (ctx, next) => {
      console.log(1); 
      await next(); 
      console.log(2); 
    });
    
    app.use(async (ctx, next) => {
      console.log(3); 
    
      await new Promise(((resolve) => {
        setTimeout(resolve, 300);
      })); 
    
      await next(); 
      console.log(4); 
    });
    
    app.use(async (ctx, next) => { 
      ctx.body = 'Hello World';
    });
    
    app.listen(3000);
    

    输出:1 3 4 2

    可见express内部执行异步函数不能确定什么时候执行完,所以生命周期并不是很确定;但是Koa是基于async/await,所以在执行下一步操作的时候,必须等待前端的await执行完,所以生命周期确定。

  • express内置eTag而koa没有

    原因同上,因为express生命周期不确定,所以不知道什么时候计算,因而内置;
    而Koa 是确定的,所以可以不用内置

  • express和koa实现计算返回时间中间件,并设置响应头X-Response-Time
    (on-finished模块可以计算响应时间,因为当请求结束的时候会执行on-finished,但是不能设置响应头,因为响应已经结束无法设置响应头)

    on-headers: 响应即将写进headers执行监听器,on-headers核心在于重写res.writeHead, res.writeHead执行于res.end()前一步,仅执行一次,因而可以用来计算请求响应时间

    Express:

    var express = require('express');
    var onHeaders = require('on-headers');
    
    // 也可以用response-time模块实现,核心原理同下面的responseTime函数
    // var responseTime = require('response-time')
    
    var app = express();
    
    // 中间件,上面responseTime的核心实现,基于on-headers模块
    function responseTime () {
        return function responseTime (req, res, next) {
          const startAt = process.hrtime()
      
          onHeaders(res, function onHeaders () {
            const diff = process.hrtime(startAt)
            const time = diff[0] * 1e3 + diff[1] * 1e-6
            res.setHeader('X-Response-Time', time.toFixed(3) + 'ms')
          })
      
          next()
        }
    }
    
    //使用中间件计算response Time
    app.use(responseTime());
    
    app.get('/', (req, res) => {    
        res.send('Hello friends!');
    });
    
    app.listen(3000);
    

    Koa:

    const Koa = require('koa');
    const app = new Koa();
    
    app.use(async (ctx, next) => {
        const start = Date.now();
        await next();
        const ms = Date.now() - start;
        ctx.set('X-Response-Time', `${ms}ms`);
    });
    
    app.use(async ctx => {
        ctx.body = 'Hello World';
    });
    
    app.listen(3000);
    
  • 异常处理
    Express 使用 Node 约定的 “error-first 回调” 处理异常,并通过中间件传播。(http://www.expressjs.com.cn/guide/error-handling.html)
    Koa 通过同步方式编写异步代码,可以通过 try catch 处理异常,非常自然。

    // Express 异常的一种写法,具体见上述链接
    app.use(function (err, req, res, next) {
      res.status(err.status || 500).send('error')
    })
    
    // Koa
    app.use(async (ctx, next) => {
      try {
        await next()
      } catch (err) {
        ctx.app.emit('error', err)
        ctx.status = err.status || 500
        ctx.body = { message: err.message }
      }
    })
    

以上基于koa 2.x版本。
扩展:
Express实现responseTime: https://github.com/expressjs/response-time
ResponseTime: https://github.com/expressjs/response-time/blob/master/index.js
onHeadesr: https://github.com/jshttp/on-headers/blob/master/index.js
Express开发总结:https://www.jianshu.com/p/f0f3f2144a3c

TODO:
node异常处理
nodejs中使用domain模块捕获异常:
https://www.jianshu.com/p/9c769c2ba914

你可能感兴趣的:(node)