express和koa的区别与联系

Express是基于 Node.js 平台,快速、开放、极简的 Web 开发框架。 Koa 是一个新的 web 框架,由 Express 幕后的原班人马打造, 致力于成为 web 应用和 API 开发领域中的一个更小、更富有表现力、更健壮的基石。 通过利用 async 函数,Koa 帮你丢弃回调函数,并有力地增强错误处理。 Koa 并没有捆绑任何中间件, 而是提供了一套优雅的方法,帮助您快速而愉快地编写服务端应用程序。


一个简单的Express服务器

  1. const express = require('express');
  2. const app = express();
  3. /* 中间件 */
  4. app.use(req,res,next)=>{
  5. console.log('这是一个中间件')
  6. next();
  7. }
  8. /* 路由部分 */
  9. const router = express.Router();
  10. router.get('/',(req,res)=>{
  11. res.send('home');
  12. })
  13. app.use(router)
  14. /* 静态文件 */
  15. app.use(express.static('./'));
  16. app.listen(3000)

一个简单的Koa服务器

  1. const Koa = require('koa');
  2. const Router = require('koa-router');
  3. const serve = require('koa-static');
  4. const app = new Koa();
  5. const router = new Router();
  6. /* 中间件 */
  7. app.use(async(ctx,next)=>{
  8. console.log('这是一个中间件')
  9. next();
  10. console.log('这是一个标记')
  11. })
  12. router.get('/',(ctx)=>{
  13. ctx.body = 'home';
  14. })
  15. app.use(router.routes());
  16. /* 静态文件 */
  17. app.use(serve('./'));
  18. app.listen(3000)

中间件的区别

在这两种框架中,中间件的执行顺序都是自上而下的,然而它们最大的区别在于:

  • Express 中间件链是基于回调的,也是node中最常见Error-First的模式(第一个参数是error对象);
  • Koa 是使用Async/Await的模式,也就是基于Promise,使用Try-Catch来捕获错误。

express的中间件是线性模型express和koa的区别 - 图1

  1. const express = require("express")
  2. const app = express();
  3. app.use("/",function(req,res,next){
  4. console.log("这是一个中间件1...")
  5. next()
  6. })
  7. app.use("/",function(req,res,next){
  8. console.log("这是一个中间件2...")
  9. next()
  10. })
  11. app.listen(3000)

输出结果:

  1. 这是一个中间件1...
  2. 这是一个中间件2...

从上述代码,可以看到,启动服务后当你访问 127.0.0.1:3000/ 的时候,就会打印出相应的内容,所以Express是线性的。

再看看下一个例子:

  1. let express = require('express');
  2. let app = express();
  3. app.use((req, res, next)=>{
  4. console.log('第一个中间件start');
  5. next()
  6. console.log('第一个中间件end');
  7. });
  8. app.use((req, res, next)=>{
  9. console.log('第二个中间件start');
  10. next()
  11. console.log('第二个中间件end');
  12. });
  13. app.listen(3000);

输出结果:

  1. 第一个中间件start
  2. 第二个中间件start
  3. 第二个中间件end
  4. 第一个中间件end

当中间件内没有异步操作时,它是这样运作的:

  1. let express = require('express');
  2. let app = express();
  3. app.use((req, res, next)=>{
  4. console.log('第一个中间件start');
  5. ((req, res, next)=>{
  6. console.log('第二个中间件start');
  7. (function handler(req, res, next) {
  8. // do something
  9. })()
  10. console.log('第二个中间件end');
  11. })()
  12. console.log('第一个中间件end');
  13. });
  14. app.listen(3000);

可以看到就是一层一层嵌套的回调,next过后继续寻找下一个中间件。

Express错误处理
所有 Express 的路由处理函数都有第三个参数next,它可以用来调用下一个中间件,也可以将错误传递给错误处理中间件:

  1. const express = require("express")
  2. const app = express();
  3. app.use((req,res,next)=>{
  4. console.log("中间件");
  5. next(new Error('错误了'))
  6. })
  7. app.get('/',(req,res)=>{
  8. res.send('你好')
  9. })
  10. /* 错误处理中间件,它有四个参数 */
  11. app.use((err,req,res,next)=>{
  12. console.log(err);
  13. })
  14. app.listen(3000)

Koa的中间件是洋葱模型:
express和koa的区别 - 图2
例子:

  1. const Koa = require('koa')
  2. const app = new Koa()
  3. app.use(async function m1 (ctx, next) {
  4. console.log('m1')
  5. await next()
  6. console.log('m1 end')
  7. })
  8. app.use(async function m2 (ctx, next) {
  9. console.log('m2')
  10. await next()
  11. console.log('m2 end')
  12. })
  13. app.use(async function m3 (ctx) {
  14. console.log('m3')
  15. ctx.body = 'hello'
  16. })
  17. app.listen(8080)

输出结果:

  1. m1
  2. m2
  3. m3
  4. m2 end
  5. m1 end

可以看到,在koa中,一切的流程都是中间件,数据流向遵循洋葱模型,先入后出,是按照类似堆栈的方式组织和执行,所有的请求经过一个中间件的时候都会执行两次,await next()后,会进入下一个中间件并执行,然后从最后一个中间件反向执行。对比 Express 形式的中间件,Koa 的模型可以非常方便的实现后置处理逻辑。

Koa异常处理

通过同步方式编写异步代码带来的另外一个非常大的好处就是异常处理非常自然,使用 try catch 就可以将按照规范编写的代码中的所有错误都捕获到。这样我们可以很便捷的编写一个自定义的错误处理中间件。

  1. async function onerror(ctx, next) {
  2. try {
  3. await next();
  4. } catch (err) {
  5. ctx.app.emit('error', err);
  6. ctx.body = 'server error';
  7. ctx.status = err.status || 500;
  8. }
  9. }

只需要将这个中间件放在其他中间件之前,就可以捕获它们所有的同步或者异步代码中抛出的异常了。