Node.js框架之express与koa对比分析

简介:


提到Node.js开发,不得不提目前炙手可热的2大框架express和koa。Express诞生已有时日,是一个简洁而灵活的web开发框架,使用简单而功能强大。Koa相对更为年轻,是Express框架原班人马基于ES6新特性重新开发的敏捷开发框架,现在可谓风头正劲,大有赶超Express之势。

Express和koa都是服务端的开发框架,服务端开发的重点是对HTTP Request和HTTP Response两个对象的封装和处理,应用的生命周期维护以及视图的处理等。 以下将主要通过这些方面,对两者进行一个对比介绍,看看到底有什么区别。

Express主要基于Connect中间件框架,功能丰富,随取随用,并且框架自身封装了大量便利的功能,比如路由、视图处理等等。而koa主要基于co中间件框架,框架自身并没集成太多功能,大部分功能需要用户自行require中间件去解决,但是由于其基于ES6 generator特性的中间件机制,解决了长期诟病的“callback hell”和麻烦的错误处理的问题,大受开发者欢迎。

Express和koa初印象

先来一个Hello World,各自认识一下吧

//Express
var express = require('express')
var app = express()  //创建一个APP实例

//建一个项目根目录的get请求路由,回调方法中直接输出字符串Hello World!
app.get('/', function (req, res) {
    res.send('Hello World!')
});

//监听端口,启动服务
app.listen(3000);

//Koa
var koa = require('koa');
var route = require('koa-route');  //koa默认没有集成route功能,引入中间件

var app = koa();  //创建一个APP实例

//建一个项目根目录的get请求路由,回调方法中直接输出字符串Hello World!,就是挂载一个中间件
app.use(route.get('/', function *(){
    this.body = 'Hello World';
}));

//监听端口,启动服务
app.listen(3000);

可以看出来,两者创建一个基础的Web服务都非常简单,可以说几行代码就解决了问题。两者的写法也基本相同,最大的区别是路由处理Express是自身集成的,而koa需要引入中间件。以下是Koa官方文档对于两者特性的一个对比:

重要功能对比介绍

Feature Koa Express Connect
Middleware Kernel
Routing
Templating
Sending Files
JSONP

通过后续的比较,大家其实可以看出,虽然koa看上去比express少集成了很多功能,但是使用起来其实基本一致,因为中间件非常丰富全面,需要什么require进来就行了(不一定要像express那样先帮你require好),使用起来反而更加灵活。

应用生命周期和上下文

我们在项目过程中,经常需要用到在整个应用生命周期中共享的配置和数据对象,比如服务URL、是否启用某个功能特性、接口配置、当前登录用户数据等等。属于比较基础的功能,两者都非常方便,koa的application context感觉使用起来更方便一点。

//Express
//共享配置,express提供了很多便利的方法
app.set('enableCache', true)
app.get('enableCache')//true

app.disable('cache')
app.disabled('cache')//true

app.enable('cache')
app.enabled('cache')//true

//应用共享数据:app.locals
app.locals.user = {name:"Samoay", id:1234};

//Koa
//配置,直接使用koa context即可
app.enableCache = true;

app.use(function *(next){
    console.log(this.app.enableCache);
    //true
    this.app.enableCache = false;

    //just use this
    this.staticPath = 'static';

    yield *next;
});

//应用共享数据:ctx.state
this.state.user = {name:"Samoay", id:1234};

请求 HTTP Request

服务器端需要进行什么处理,怎么处理以及处理的参数都依赖客户端发送的请求,两个框架都封装了HTTP Request对象,便于对这一部分进行处理。以下主要举例说明下对请求参数的处理,其它例如头信息、Cookie等请参考官方文档。两者除了写法上稍有区别,没太大区别。GET参数都可以直接通过Request对象获取,POST参数都需要引入中间件先parse,再取值。

// Express
// 获取QueryString参数
// GET /shoes?order=desc&shoe[color]=blue
req.query.order
// => "desc"

req.query.shoe.color
// => "blue"

// 通过路由获取Restful风格的URL参数
app.get('/user/:id?', function userIdHandler(req, res) {
    console.log(req.params.id);
    res.send('GET');
})

//获取POST数据:需要body-parser中间件
var bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({ extended: true }));
app.post('/', function (req, res) {
    console.log(req.body);
    res.json(req.body);
})

// 获取QueryString参数
// GET /?action=delete&id=1234
this.request.query
// => { action: 'delete', id: '1234' }

// 通过路由获取Restful风格的URL参数
var route = require('koa-route');
app.use(route.get('/post/:id', function *(id){
    console.log(id);
    // => 1234
}));

// 获取POST数据:需要co-body中间件
// Content-Type: application/x-www-form-urlencoded
// title=Test&content=This+is+a+test+post
var parse = require('co-body');
app.use(route.post('/post/new', function *(){
    var post = yield parse(this.request);//this
    console.log(post);
    // => { title: 'Test', content: 'This is a test post' }
}));

路由 Route

收到客户端的请求,服务需要通过识别请求的方法(HTTP Method: GET, POST, PUT...)和请求的具体路径(path)来进行不同的处理。这部分功能就是路由(Route)需要做的事情,说白了就是请求的分发,分发到不同的回调方法去处理。

// Express
// app.all表示对所有的路径和请求方式都要经过这些回调方法的处理,可以逗号方式传入多个
app.all('*', authentication, loadUser);
// 也可以多次调用
app.all('*', requireAuthentication)
app.all('*', loadUser);
// 也可以针对某具体路径下面的所有请求
app.all('/api/*', requireAuthentication);

// app.get GET方式的请求
app.get('/user/:id', function(req, res) {
    res.send('user ' + req.params.id);
});

// app.post  POST方式的请求
app.post('/user/create', function(req, res) {
    res.send('create new user');
});

这里需要说明2个问题,首先是app.get,在应用生命周期中也有一个app.get方法,用于获取项目配置。Express内部就是公用的一个方法,如果传入的只有1个参数就获取配置,2个参数就作为路由处理。其次是app.use('*', cb) 与app.all('*', cb) 的区别,前者是中间件方式,调用是有顺序的,不一定会执行到;后者是路由方式,肯定会执行到。


// Koa
// 和Express不同,koa需要先引入route中间件
var route = require('koa-route');

//引入中间件之后支持的写法差不多,只是路径传入route,然后把route作为中间件挂载到app
app.use(route.get('/', list));
app.use(route.get('/post/new', add));
app.use(route.get('/post/:id', show));
app.use(route.post('/post', create));

//链式写法
var router = require('koa-router')();

router.get('/', list)
      .get('/post/new', add)
      .get('/post/:id', show)
      .post('/post', create);

app.use(router.routes())
   .use(router.allowedMethods());

视图 Views

Express框架自身集成了视图功能,提供了consolidate.js功能,可以是有几乎所有Javascript模板引擎,并提供了视图设置的便利方法。Koa需要引入co-views中间件,co-views也是基于consolidate.js,支持能力一样强大。

// Express
// 这只模板路径和默认的模板后缀
app.set('views', __dirname + '/tpls');
app.set('view engine', 'html');

//默认,express根据template的后缀自动选择模板
//引擎渲染,支持jade和ejs。如果不使用默认扩展名
app.engine(ext, callback)

app.engine('html', require('ejs').renderFile);

//如果模板引擎不支持(path, options, callback)
var engines = require('consolidate');
app.engine('html', engines.handlebars);
app.engine('tpl', engines.underscore);

app.get('list', function(res, req){
    res.render('list', {data});
});

//Koa
//需要引入co-views中间件
var views = require('co-views');

var render = views('tpls', {
    map: { html: 'swig' },//html后缀使用引擎
    default: "jade"//render不提供后缀名时
});

var userInfo = {
    name: 'tobi',
    species: 'ferret'
};

var html;
html = render('user', { user: userInfo });
html = render('user.jade', { user: userInfo });
html = render('user.ejs', { user: userInfo });

返回 HTTP Response

获取完请求参数、处理好了具体的请求、视图也准备就绪,下面就该返回给客户端了,那就是HTTP Response对象了。这部分也属于框架的基础部分,各种都做了封装实现,显著的区别是koa直接将输出绑定到了ctx.body属性上,另外输出JSON或JSONP需要引入中间件。

// Express
//输出普通的html
res.render('tplName', {data});

//输出JSON
res.jsonp({ user: 'Samoay' });
// => { "user": "Samoay" }

//输出JSONP   ?callback=foo
res.jsonp({ user: 'Samoay' });
// => foo({ "user": "Samoay" });

//res.send([body]);
res.send(new Buffer('whoop'));
res.send({ some: 'json' });
res.send('<p>some html</p>');

//设定HTTP Status状态码
res.status(200);

//koa直接set ctx的status和body
app.use(route.get('/post/update/:id', function *(id){
    this.status = 404;
    this.body = 'Page Not Found';
}));

var views = require('co-views');
var render = views('tpls', {
    default: "jade"//render不提供后缀名时
});
app.use(route.get('/post/:id', function *(id){
    var post = getPost(id);
    this.status = 200;//by default, optional
    this.body = yield render('user', post);
}));

//JSON
var json = require('koa-json');
app.use(route.get('/post/:id', function *(id){
    this.body = {id:1234, title:"Test post", content:"..."};
}));

中间件 Middleware

对比了主要的几个框架功能方面的使用,其实区别最大,使用方式最不同的地方是在中间件的处理上。Express由于是在ES6特性之前的,中间件的基础原理还是callback方式的;而koa得益于generator特性和co框架(co会把所有generator的返回封装成为Promise对象),使得中间件的编写更加优雅。

// req 用于获取请求信息, ServerRequest 的实例
// res 用于响应处理结果, ServerResponse 的实例
// next() 函数用于将当前控制权转交给下一步处理,
//        如果给 next() 传递一个参数时,表示出错信息
var x = function (req, res, next) {

    // 对req和res进行必要的处理

    // 进入下一个中间件
    return next();

    // 传递错误信息到下一个中间件
    return next(err);

    // 直接输出,不再进入后面的中间件
    return res.send('show page');
};

// koa 一切都在ctx对象上+generator
app.use(function *(){
    this; // is the Context

    this.request; // is a koa Request
    this.response; // is a koa Response

    this.req;// is node js request
    this.res;// is node js response

    //不再进入后面的中间件, 回溯upstream
    return;
});


该文章来自于阿里巴巴技术协会( ATA

作者:金鸿

目录
相关文章
|
16天前
|
Web App开发 JavaScript 前端开发
深入浅出Node.js后端框架
【10月更文挑战第34天】在数字化时代,后端开发如同一座桥梁,连接着用户界面与数据处理的两端。本文将通过Node.js这一轻量级、高效的平台,带领读者领略后端框架的魅力。我们将从基础概念出发,逐步深入到实战应用,最后探讨如何通过代码示例来巩固学习成果,使读者能够在理论与实践之间架起自己的桥梁。
|
23小时前
|
JavaScript
如何使用内存快照分析工具来分析Node.js应用的内存问题?
需要注意的是,不同的内存快照分析工具可能具有不同的功能和操作方式,在使用时需要根据具体工具的说明和特点进行灵活运用。
17 3
|
4天前
|
缓存 监控 JavaScript
Vue.js 框架下的性能优化策略与实践
Vue.js 框架下的性能优化策略与实践
|
5天前
|
缓存 负载均衡 JavaScript
构建高效后端服务:Node.js与Express框架实践
在数字化时代的浪潮中,后端服务的重要性不言而喻。本文将通过深入浅出的方式介绍如何利用Node.js及其强大的Express框架来搭建一个高效的后端服务。我们将从零开始,逐步深入,不仅涉及基础的代码编写,更会探讨如何优化性能和处理高并发场景。无论你是后端新手还是希望提高现有技能的开发者,这篇文章都将为你提供宝贵的知识和启示。
|
10天前
|
JavaScript 前端开发 API
Vue.js与Angular的优劣分析
Vue.js和Angular都是非常流行的JavaScript框架,它们在构建现代Web应用程序方面各有优劣
|
15天前
|
运维 监控 JavaScript
鸿蒙next版开发:分析JS Crash(进程崩溃)
在HarmonyOS 5.0中,JS Crash指未处理的JavaScript异常导致应用意外退出。本文详细介绍如何分析JS Crash,包括异常捕获、日志分析和典型案例,帮助开发者定位问题、修复错误,提升应用稳定性。通过DevEco Studio收集日志,结合HiChecker工具,有效解决JS Crash问题。
37 4
|
17天前
|
Web App开发 JavaScript 前端开发
探索后端开发:Node.js与Express的完美结合
【10月更文挑战第33天】本文将带领读者深入了解Node.js和Express的强强联手,通过实际案例揭示它们如何简化后端开发流程,提升应用性能。我们将一起探索这两个技术的核心概念、优势以及它们如何共同作用于现代Web开发中。准备好,让我们一起开启这场技术之旅!
32 0
|
17天前
|
Web App开发 JavaScript 前端开发
构建高效后端服务:Node.js与Express框架的实践
【10月更文挑战第33天】在数字化时代的浪潮中,后端服务的效率和可靠性成为企业竞争的关键。本文将深入探讨如何利用Node.js和Express框架构建高效且易于维护的后端服务。通过实践案例和代码示例,我们将揭示这一组合如何简化开发流程、优化性能,并提升用户体验。无论你是初学者还是有经验的开发者,这篇文章都将为你提供宝贵的见解和实用技巧。
|
1月前
|
JavaScript 前端开发 中间件
探索后端技术:Node.js与Express框架的完美融合
【10月更文挑战第7天】 在当今数字化时代,Web应用已成为日常生活不可或缺的一部分。本文将深入探讨后端技术的两大重要角色——Node.js和Express框架,分析它们如何通过其独特的特性和优势,为现代Web开发提供强大支持。我们将从Node.js的非阻塞I/O和事件驱动机制,到Express框架的简洁路由和中间件特性,全面解析它们的工作原理及应用场景。此外,本文还将分享一些实际开发中的小技巧,帮助你更有效地利用这些技术构建高效、可扩展的Web应用。无论你是刚入门的新手,还是经验丰富的开发者,相信这篇文章都能为你带来新的启发和思考。
|
1月前
|
开发框架 JavaScript 前端开发
使用 Node.js 和 Express 构建 Web 应用
【10月更文挑战第2天】使用 Node.js 和 Express 构建 Web 应用
下一篇
无影云桌面