Node.js框架对比:Express/Koa/Hapi
引言
Express.js是当今使用最广泛的Node.js Web应用程序框架。它似乎是大多数Node.js Web应用程序中的基本依赖项,即使某些流行的框架(如Sails.js)也是基于Express构建的。但是,有更多选项对他们具有相同的“ sinatra风格”感觉。接下来的两个最受欢迎的框架分别是Koa和Hapi。
这并不是说服您使用一个框架,而是要帮助您更好地了解每个框架可以做什么以及在什么地方可能胜过另一个框架。
框架背景
我们将要研究的所有三个框架都有很多共同点。所有人都可以只用几行代码就可以创建服务器,而且一切都使得创建REST API非常简单。让我们看看这些框架是如何开始的。
2.1 Express
TJ Holowaychuk于6月26日对Express进行了最初的提交,而1月2日发布了660则0.0.1版的更新。当时的两个主要贡献者是TJ和Ciaron Jessup。在第一个发行版时,该框架根据github上的readme.md进行了描述。
建立在node.js和V8 JavaScript引擎之上的快速(小型)服务器端JavaScript Web开发框架。
快进近5年,提交4,925次提交,现在4.10.1是StrongLoop维护的最新版本,因为TJ现在正集中在Go-Lang社区中。
2.2 Koa
对Koa的最初承诺是在一年多以前,即8月17日,当时TJ Holowaychuk对此毫无保留。他将其描述为“用于通过使用co生成器的node.js的表达中间件,使编写Web应用程序和REST API的编写更加令人愉快”。宣传Koa的足迹很小,约为400 SLOC。现在,它在0.13.0版本中有585次提交。
2.3 Hapi
Hapi的最初提交是在8月5日,由WalmartLabs的成员Eran Hammer进行。Hapi由Postmile的一部分创建,最初是在Express之上构建的。后来由于Erin state在他的博客中的内容,它被开发成自己的框架:
创建hapi的想法是配置比代码更好,业务逻辑必须与传输层隔离...
3,816次提交,以后Hapi的版本为7.2.0,仍由Eran Hammer维护。
最后,让我们看看一些社区统计数据,以了解这些框架的受欢迎程度:
创建服务器
对于任何开发人员而言,在使用Node.js Web应用程序时,第一步是创建一个基本服务器。因此,让我们使用每个框架创建一个服务器来查看它们的异同。
3.1 快递
var express = require('express');var app = express();var server = app.listen(3000, function() {console.log('Express is listening to http://localhost:3000');});
对于所有节点开发人员来说,这可能是很自然的。我们需要express,然后通过将其分配给变量来实例化它app
。然后实例化服务器以监听端口3000。app.listen()
实际上,它实际上只是节点的包装http.createServer()
。
3.2 Koa
var koa = require('koa');var app = koa();var server = app.listen(3000, function() {console.log('Koa is listening to http://localhost:3000');});
马上,您会看到Koa与Express相似。本质上,您只需要koa而不是express。也app.listen()
与Express中使用的包装器功能完全相同。
3.3哈皮
var Hapi = require('hapi');var server = new Hapi.Server(3000);server.start(function() {console.log('Hapi is listening to http://localhost:3000');});
哈皮(Hapi)是该集团中独一无二的一家。首先,像往常一样,需要hapiapp
,而不是实例化hapi,而是创建一个新的Server并指定端口。在Express和Koa中,我们获得了一个回调函数,而在Hapi中,我们获得了一个新server
对象。然后,一旦调用,server.start()
我们就在端口3000上启动服务器,然后返回回调。但是,这不像Koa和Express,它不是包装器http.CreateServer()
,而是使用了自己的逻辑。
路由
现在,让我们深入探讨服务器最重要的功能之一,即路由。首先,让我们为每个框架创建俗套的“ Hello world”应用程序,然后继续使用其他有用的REST API。
4.1Hello World
4.1.1快递
var express = require('express');var app = express();app.get('/', function(req, res) {res.send('Hello world');});var server = app.listen(3000, function() {console.log('Express is listening to http://localhost:3000');});
我们正在使用该get()
方法来捕获传入的“ GET /”请求,然后调用处理两个参数req
和的回调函数res
。在此示例中,我们仅利用res
来将字符串返回给页面res.send()
。Express具有用于处理路由功能的多种内置方法。下面是一些由快递支持的较常用的方法(但不是所有的方法)get
,post
,put
,head
,delete
...
4.1.2 Koa
var koa = require('koa');var app = koa();app.use(function *() {this.body = 'Hello world';});var server = app.listen(3000, function() {console.log('Koa is listening to http://localhost:3000');});
Koa与Express略有不同,它使用的是ES6生成器。任何以“。”开头*
的函数都将返回一个生成器对象。基本上,这些生成器会yield
同步值,但这超出了本文的范围。在app.use()
generator函数内设置响应主体。在Koa中Context
,等同于this
标识符的是节点request
和response
对象的封装。this.body
是KoaResponse
对象中的方法。this.body
可以设置为字符串,缓冲区,流,对象或null。在这个示例中,我们使用了Koa核心中提供的少数中间件之一。我们使用的这个中间件捕获所有路由并以提供的字符串进行响应。
4.1.3哈皮
var Hapi = require('hapi');var server = new Hapi.Server(3000);server.route({method: 'GET',path: '/',handler: function(request, reply) {reply('Hello world');}});server.start(function() {console.log('Hapi is listening to http://localhost:3000');});
在这里,我们使用该server
对象提供给我们的内置方法,该方法server.route()
具有以下选项:(path
必需),method
(必需)vhost
,和handler
(必需)。HTTP方法可以处理典型请求GET
,PUT
,POST
,DELETE
,和*
其抓住的任何途径。处理程序将传递对该request
对象的引用,并且必须reply
使用包含的有效负载进行调用。有效负载可以是字符串,缓冲区,可序列化的对象或流。
4.2 REST API
除了显示最基本/最简单的启动和运行应用程序的方式外,Hello世界从没有真正做过什么。REST API在所有数据密集型应用程序中几乎都是必需的,并且将有助于更好地了解如何使用这些框架。因此,让我们看一下它们如何处理REST API。
4.2.1快递
var express = require('express');var app = express();var router = express.Router(); // REST APIrouter.route('/items').get(function(req, res, next) {res.send('Get');}).post(function(req, res, next) {res.send('Post');});router.route('/items/:id').get(function(req, res, next) {res.send('Get id: ' + req.params.id);}).put(function(req, res, next) {res.send('Put id: ' + req.params.id);}).delete(function(req, res, next) {res.send('Delete id: ' + req.params.id);});app.use('/api', router);// indexapp.get('/', function(req, res) {res.send('Hello world');});var server = app.listen(3000, function() {console.log('Express is listening to http://localhost:3000');});
因此,我们将REST API添加到了现有的Hello World应用程序中。Express提供了一些处理路线的捷径。这是Express 4.x语法,但在Express 3.x中基本上相同,除了不需要,express.Router()
并且将无法使用该行app.use('/api', router)
。相反,您将在现有动词之前router.route()
加上来替换的。这是一个很好的方法,因为它减少了开发人员出错的机会,并最小化了更改HTTP方法动词的位置。app.route()
/api
4.2.2 Koa
var koa = require('koa');var route = require('koa-route');var app = koa();// REST APIapp.use(route.get('/api/items', function*() {this.body = 'Get';}));app.use(route.get('/api/items/:id', function*(id) {this.body = 'Get id: ' + id;}));app.use(route.post('/api/items', function*() {this.body = 'Post';}));app.use(route.put('/api/items/:id', function*(id) {this.body = 'Put id: ' + id;}));app.use(route.delete('/api/items/:id', function*(id) {this.body = 'Delete id: ' + id;}));// all other routesapp.use(function *() {this.body = 'Hello world';});var server = app.listen(3000, function() {console.log('Koa is listening to http://localhost:3000');});
很明显,Koa没有能力减少像Express这样的重复路线动词。它还需要一个单独的中间件来处理路由。我之所以选择使用koa-route
,是因为它是由Koa团队维护的,但是其他维护者可以使用很多路由。这些路线非常相似,快递与使用相同的关键字为他们的方法调用喜欢.get()
,.put()
,.post()
,和.delete()
。Koa处理路由的一个优势是,它使用了ES6生成器函数,该函数有助于减少对回调的处理。
4.2.3哈皮
var Hapi = require('hapi');var server = new Hapi.Server(3000);server.route([{method: 'GET',path: '/api/items',handler: function(request, reply) {reply('Get item id');}},{method: 'GET',path: '/api/items/{id}',handler: function(request, reply) {reply('Get item id: ' + request.params.id);}},{method: 'POST',path: '/api/items',handler: function(request, reply) {reply('Post item');}},{method: 'PUT',path: '/api/items/{id}',handler: function(request, reply) {reply('Put item id: ' + request.params.id);}},{method: 'DELETE',path: '/api/items/{id}',handler: function(request, reply) {reply('Delete item id: ' + request.params.id);}},{method: 'GET',path: '/',handler: function(request, reply) {reply('Hello world');}}]);server.start(function() {console.log('Hapi is listening to http://localhost:3000');});
Hapi中路由的第一印象是它们与其他框架相比具有多么的清洁和可读性。即使所需的选项method
,path
,handler
,和replay
对路线很容易对眼睛。像Koa一样,有大量的代码重用,使错误的余地更大。但是,这是有意的,Hapi更加关注配置,并希望代码更整洁,以便在团队中更轻松地使用。Hapi还希望改进错误处理,而无需在开发人员端编写任何代码。如果您尝试查找未在REST API中描述的路由,它将返回一个带有状态代码和错误描述的JSON对象。
5优劣势
5.1快递 Express
5.1.1好
Express不仅在这里比较的三个框架中而且在Node.js的所有Web应用程序框架中都拥有最大的社区。它是三个框架中最成熟的框架,它拥有近5年的开发经验,现在由StrongLoop来控制存储库。它提供了一种使服务器启动并运行的简单方法,并利用其内置的路由器促进了代码重用。
5.1.2坏
Express中涉及许多手动繁琐的任务。没有内置的错误处理,很容易迷失在可以添加来解决解决方案的所有中间件中,并且有很多方法可以做一件事情。Express自称是固执己见,这可能是好是坏,但对于必须选择Express的新手开发人员来说,这是一件坏事。与其他框架相比,Express的足迹也更大。
5.2 Koa
5.2.1好
Koa占用空间小,更具表现力,并且使中间件的编写比其他框架容易得多。Koa基本上是一个准系统框架,开发人员可以在其中选择(或编写)他们要使用的中间件,而不会破坏Express或Hapi随附的中间件。这是唯一包含ES6的框架,例如使用ES6生成器的框架。
5.2.2不好
Koa仍然不稳定并且正在大量开发中。使用ES6仍然领先于游戏,例如需要使用Node.js的0.11.9+版本来运行Koa,现在Node.js上的最新稳定版本为0.10.33。选择Express或编写自己的中间件是一件好事,但也有可能像Express一样坏事。例如我们之前看过的路由器,有很多中间件路由器可以处理各种选项。
5.3哈皮 Hapi
5.3.1好
Hapi自豪地说他们的框架基于代码之上的配置,许多开发人员会认为这是一件好事。这在大型团队中很常见,以增加一致性和可重用性。此外,在沃尔玛实验室以及许多其他在生产中使用Hapi的知名公司支持该框架的情况下,该框架已经进行了实战测试,公司有足够的信心从中运行其应用程序。因此,种种迹象表明,该项目将继续发展成为一个很好的框架。
5.3.2坏
Hapi显然似乎更适合于更大或更复杂的应用程序。放在一起一个简单的Web应用程序可能需要太多样板代码,并且使用hapi的示例或开源应用程序也很多。因此,选择它可能会涉及开发人员更多的部分,而不是使用第三方中间件。
6小结
我们已经看到了所有这三个框架的一些不错但实用的示例。Express绝对是这三个框架中最受欢迎和最受认可的框架。在应用程序上开始新开发时,首先使用Express创建服务器几乎是一种反应,但希望现在可能会涉及到一些考虑是否使用Koa或Hapi作为替代方案。Koa展现了对未来的真正希望,并且在拥抱ES6和Web开发社区正在迈向的Web组件思想方面遥遥领先。Hapi应该是大型团队和大型项目的首要考虑因素。它推动通过代码进行配置,这几乎总是使团队受益,并且大多数团队都在努力实现可重用性。现在,出去尝试一个新的框架,也许您会喜欢它,也许您会讨厌,但是您永远不会知道,最后,