node.js Express 和 hapi 相比如何?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/30469767/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 18:48:05  来源:igfitidea点击:

How do Express and hapi compare to each other?

node.jsexpressframeworkshapijs

提问by Ali Shakiba

From web application design and development point of view, how do Express and Hapi compare to each other? For basic examples they seem similar, however I'm interested to learn more about key differences in overall application structure.

从 Web 应用程序设计和开发的角度来看,Express 和 Hapi 相比如何?对于基本示例,它们看起来很相似,但是我有兴趣了解更多有关整体应用程序结构的主要差异的信息。

For example, as far as I have learned, Hapi uses a differentrouting mechanism which does not take registration order into account, can do faster lookups, but is limited comparing to Express. Are there other important differences?

例如,据我所知,Hapi 使用了不同的路由机制,它不考虑注册顺序,可以进行更快的查找,但与 Express 相比有局限性。还有其他重要的区别吗?

There is also an articleabout choosing Hapi (over Express) for developing the new npmjs.com website, this article states that "Hapi's plugin system means that we can isolate different facets and services of the application in ways that would allow for microservices in the future. Express, on the other hand, requires a bit more configuration to get the same functionality", what does it exactly mean?

还有一篇关于选择 Hapi(而不是 Express)来开发新的 npmjs.com 网站的文章,这篇文章指出“Hapi 的插件系统意味着我们可以以允许微服务的方式隔离应用程序的不同方面和服务未来。另一方面,Express 需要更多配置才能获得相同的功能”,这到底是什么意思?

回答by Matt Harrison

This is a big question and requires a long answer to be complete, so I'll just address a subset of the most important differences. Apologies that it's still a lengthy answer.

这是一个很大的问题,需要很长的答案才能完整,所以我将只解决最重要差异的一个子集。很抱歉,这仍然是一个冗长的答案。

How are they similar?

他们有什么相似之处?

You're absolutely right when you say:

当你说:

For basic examples they seem similar

对于基本示例,它们看起来很相似

Both frameworks are solving the same basic problem: Providing a convenient API for building HTTP servers in node. That is to say, more convenient than using the lower-level native httpmodule alone. The httpmodule can do everything we want but it's tedious to write applications with.

这两个框架都在解决相同的基本问题:为在 node.js 中构建 HTTP 服务器提供方便的 API。也就是说,比http单独使用下层原生模块方便多了。该http模块可以做我们想做的一切,但编写应用程序很乏味。

To achieve this, they both use concepts that have been around in high level web frameworks for a long time: routing, handlers, plugins, authentication modules. They might not have always had the same names but they're roughly equivalent.

为了实现这一点,他们都使用了高级 Web 框架中长期存在的概念:路由、处理程序、插件、身份验证模块。它们可能并不总是具有相同的名称,但它们大致相同。

Most of the basic examples look something like this:

大多数基本示例如下所示:

  • Create a route
  • Run a function when the route is requested, preparing the response
  • Respond to the request
  • 创建路线
  • 在请求路由时运行函数,准备响应
  • 响应请求

Express:

表达:

app.get('/', function (req, res) {

    getSomeValue(function (obj) {

        res.json({an: 'object'});
    });
});

hapi:

哈皮:

server.route({
    method: 'GET',
    path: '/',
    handler: function (request, reply) {

        getSomeValue(function (obj) {

            reply(obj);
        });
    }
});

The difference is not exactly groundbreaking here right? So why choose one over the other?

这里的差异并不完全是开创性的,对吗?那么为什么要选择一个呢?

How are they different?

它们有何不同?

The simple answer is hapi is a lot more and it does a lot more out-of-the-box. That might not be clear when you just look at the simple example from above. In fact, this is intentional. The simple cases are kept simple. So let's examine some of the big differences:

简单的答案是 hapi 多得多,而且开箱即用。当您仅查看上面的简单示例时,这可能不清楚。事实上,这是故意的。简单的情况保持简单。因此,让我们检查一些重大差异:

Philosophy

哲学

Express is intended to be very minimal. By giving you a small API with just a thin dusting on top of http, you're still very much on your own in terms of adding additional functionality. If you want to read the body of an incoming request (quite a common task), you need to install a separate module. If you're expecting various content-types to be sent to that route, you also need to check the Content-typeheader to check which it is and parse it accordingly (form-data vs JSON vs multi-part for example), often using separate modules.

Express 旨在非常小。通过为您提供一个小 API,在 之上只添加了一层薄薄的灰尘http,就添加附加功能而言,您仍然非常依赖自己。如果要读取传入请求的正文(非常常见的任务),则需要安装一个单独的模块。如果您希望将各种内容类型发送到该路由,您还需要检查Content-type标头以检查它是哪个并相应地解析它(例如,表单数据 vs JSON vs 多部分),通常使用单独的模块.

hapi has a rich feature set, often exposed through configuration options, rather than requiring code to be written. For instance, if we want to make sure a request body (payload) is fully read into memory and appropriately parsed (automatically based on content-type) before the handler is ran, it's just a simple option:

hapi 具有丰富的功能集,通常通过配置选项公开,而不需要编写代码。例如,如果我们想确保在运行处理程序之前将请求正文(有效负载)完全读入内存并进行适当解析(自动基于内容类型),这只是一个简单的选项

server.route({
    config: {
        payload: {
            output: 'data',
            parse: true
        }
    },
    method: 'GET',
    path: '/',
    handler: function (request, reply) {

        reply(request.payload);
    }
});

Features

特征

You only need to compare the API documentation on both projects to see that hapi offers a bigger feature set.

您只需要比较两个项目的 API 文档即可看到 hapi 提供了更大的功能集。

hapi includes some of the following features built-in that Express does not (as far as I know):

hapi 包含以下一些 Express 没有的内置功能(据我所知):

Extensibility & modularity

可扩展性和模块化

hapi and Express go about extensibility in quite a different way. With Express, you have middlewarefunctions. Middleware functions are kind of like filters that you stack up and all requests run through them before hitting your handler.

hapi 和 Express 以完全不同的方式实现可扩展性。使用 Express,您拥有中间件功能。中间件函数有点像你堆叠的过滤器,所有请求在到达你的处理程序之前都会通过它们。

hapi has the request lifecycleand offers extension points, which are comparable to middleware functions but exist a several defined points in the request lifecycle.

hapi 具有请求生命周期并提供扩展点,类似于中间件功能,但在请求生命周期中存在几个定义的点。

One of the reasons that Walmart built hapi and stopped using Express was a frustration with how difficult it was to split a Express app into separate parts, and have different team members work safely on their chunk. For this reason they created the plugin systemin hapi.

沃尔玛构建 hapi 并停止使用 Express 的原因之一是,将 Express 应用程序拆分为不同的部分并让不同的团队成员安全地工作是多么困难,这让他们感到沮丧。出于这个原因,他们在 hapi 中创建了插件系统

A plugin is like a sub-application, you can do everything you can in a hapi app, add routes, extensions points etc. In a plugin you can be sure that you're not breaking another part of the application, because the order of registrations for routes doesn't matter and you can't create conflicting routes. You can then combine this plugins into a server and deploy it.

插件就像一个子应用程序,你可以在 hapi 应用程序中做你能做的一切,添加路由,扩展点等。在插件中,你可以确保你不会破坏应用程序的另一部分,因为顺序路线的注册无关紧要,您不能创建冲突的路线。然后,您可以将此插件组合到服务器中并进行部署。

Ecosystem

生态系统

Because Express gives you so little out of the box, you need to look outside when you need to add anything to your project. A lot of the times when working with hapi, the feature that you need is either built-in or there's a module created by the core team.

因为 Express 为您提供的开箱即用很少,所以当您需要向项目添加任何内容时,您需要向外看。很多时候使用 hapi 时,您需要的功能要么是内置的,要么是核心团队创建的模块。

Minimal sounds great. But if you're building a serious production app, the chances are you're going to need all of this stuff eventually.

最小听起来很棒。但是,如果您正在构建一个严肃的生产应用程序,那么您最终很有可能需要所有这些东西。

Security

安全

hapi was designed by the team at Walmart to run Black Friday traffic so security and stability have always been a top concern. For this reason the framework does a lot of things extra such as limiting incoming payload size to prevent exhausting your process memory. It also has options for things like max event loop delay, max RSS memory used and max size of the v8 heap, beyond which your server will respond with a 503 timeout rather than just crashing.

hapi 是由 Walmart 的团队设计的,用于运行黑色星期五的交通,因此安全性和稳定性一直是头等大事。出于这个原因,该框架做了很多额外的事情,例如限制传入的有效负载大小以防止耗尽您的进程内存。它还具有诸如最大事件循环延迟、最大 RSS 内存使用和 v8 堆的最大大小之类的选项,超过这些选项,您的服务器将响应 503 超时,而不仅仅是崩溃。

Summary

概括

Evaluate them both yourself. Think about your needs and which of the two addresses your biggest concerns. Have a dip in the two communities (IRC, Gitter, Github), see which you prefer. Don't just take my word. And happy hacking!

自己评估一下。考虑您的需求,两者中的哪一个解决了您最大的担忧。在两个社区(IRC、Gitter、Github)中体验一下,看看你更喜欢哪个。不要只相信我的话。和快乐的黑客!



DISCLAIMER: I am biased as the author of a book on hapiand the above is largely my personal opinion.

免责声明:作为一本关于 hapi的作者,我有偏见,以上主要是我的个人观点。

回答by wle8300

My organization is going with Hapi. This is why we like it.

我的组织正在与 Hapi 合作。这就是我们喜欢它的原因。

Hapi is:

哈皮是:

  • Backed by major corps. This means the community support will be strong, and there for you throughout future releases. It's easy to find passionate Hapi people, and there are good tutorials out there (though not as numerous and sprawling as ExpressJs tutorials). As of this post date npm and Walmart use Hapi.
  • It can facilitate the work of distributed teams working on various parts of the backend services without having to have comprehensive knowledge of the rest of the API surface (Hapi's plugins architecture is the epitome of this quality).
  • Let the framework do what a framework is supposed to: configure things. After that the framework should be invisible and allow devs to focus their real creative energy on building out business logic. After using Hapi for a year, I definitely feel Hapi accomplishes this. I... feel happy!
  • 得到大军的支持。这意味着社区支持将非常强大,并且在未来的版本中为您提供支持。很容易找到热情的 Hapi 人,并且那里有很好的教程(虽然不像 ExpressJs 教程那样多且庞大)。截至本文发布日期,npm 和 Walmart 使用 Hapi。
  • 它可以促进分布式团队在后端服务的各个部分工作,而无需全面了解 API 表面的其余部分(Hapi 的插件架构是这种质量的缩影)。
  • 让框架做框架应该做的事情:配置东西。之后,该框架应该是不可见的,并允许开发人员将他们真正的创造性精力集中在构建业务逻辑上。用了一年Hapi,我绝对觉得Hapi做到了。我感到开心!

If you want to hear directly from Eran Hammer (Hapi's lead)

如果您想直接听取 Eran Hammer(Hapi 的领导)的意见

Over the past four years hapi grew to be the framework of choice for many projects, big or small. What makes hapi unique is its ability to scale to large deployments and large teams. As a project grows, so does its complexity – engineering complexity and process complexity. hapi's architecture and philosophy handles the increased complexity without the need to constantly refactor the code [read more]

在过去的四年中,hapi 逐渐成为许多大小项目的首选框架。hapi 的独特之处在于它能够扩展到大型部署和大型团队。随着项目的增长,其复杂性也会增加——工程复杂性和过程复杂性。hapi 的架构和理念可以处理增加的复杂性,而无需不断重构代码[阅读更多]

Getting started with Hapi won't be as easy as ExpressJs because Hapi doesn't have the same "star power"... but once you feel comfortable you'll get A LOT of mileage. Took me about ~2 months as a new hacker who irresponsibly used ExpressJs for a few years. If you're a seasoned backend developer you'll know how to read the docs, and you probably won't even notice this.

开始使用 Hapi 不会像 ExpressJs 那样容易,因为 Hapi 没有相同的“明星力量”……但是一旦你感到舒服,你就会获得很多里程。作为一个不负责任地使用 ExpressJs 几年的新黑客,我花了大约 2 个月的时间。如果您是一位经验丰富的后端开发人员,您就会知道如何阅读文档,而您甚至可能不会注意到这一点。

Areas the Hapi documentation can improve on:

Hapi 文档可以改进的领域:

  1. how to authenticate users and create sessions
  2. handling Cross-Origin-Requests (CORS)
  3. uploading files (multipart, chunked)
  1. 如何验证用户和创建会话
  2. 处理跨域请求 (CORS)
  3. 上传文件(多部分,分块)

I think authentication would be the most challenging part of it because you have to decide on what kinda auth strategy to use (Basic Authentication, Cookies, JWT Tokens, OAuth). Though it's technically not Hapi's problem that the sessions/authentication landscape is so fragmented... but I do wish that they provided some hand-holding for this. It would greatly increase developer happiness.

我认为身份验证将是其中最具挑战性的部分,因为您必须决定使用哪种身份验证策略(基本身份验证、Cookie、JWT 令牌、OAuth)。尽管从技术上讲,会话/身份验证环境如此分散并不是 Hapi 的问题……但我确实希望他们为此提供一些帮助。这将大大增加开发人员的幸福感。

The remaining two aren't actually that difficult, the docs could just be written slightly better.

剩下的两个实际上并不难,文档可以写得稍微好一点。

回答by user9961607

Quick Facts about Hapi Or Why Hapi JS ?

关于 Hapi 或为什么选择 Hapi JS 的快速事实?

Hapi is configuration-centric It has authentication and authorization built into the framework It was released in a battle-tested atmosphere and has really proven its worth All the modules have 100% test coverage It registers the highest level of abstraction away from core HTTP Easily compassable via the plugin architecture

Hapi 以配置为中心 框架中内置了身份验证和授权 在经过实战考验的氛围中发布并真正证明了其价值 所有模块都具有 100% 的测试覆盖率 它注册了远离核心 HTTP 的最高抽象级别 易于理解通过插件架构

Hapi is a better choice performance wise Hapi uses a different routing mechanism, which can do faster lookups, and take registration order into account. Nevertheless, it is quite limited when compared to Express. And thanks to the Hapi plugin system, it is possible to isolate the different facets and services that would help the application in many ways in the future.

Hapi 是性能明智的更好选择 Hapi 使用不同的路由机制,可以进行更快的查找,并考虑注册顺序。然而,与 Express 相比,它是相当有限的。多亏了 Hapi 插件系统,可以隔离不同的方面和服务,这些方面和服务将在未来以多种方式帮助应用程序。

Usage

用法

Hapi is the most preferred framework when compared to Express. Hapi is used mainly for large-scale enterprise applications.

与 Express 相比,Hapi 是最受欢迎的框架。Hapi 主要用于大型企业应用。

A couple of reasons why developers do not choose Express when creating enterprise applications are:

开发人员在创建企业应用程序时不选择 Express 的几个原因是:

Routes are harder to compose in Express

路由在 Express 中更难编写

Middleware gets in the way most of the time; each time you are defining the routes, you have to write as many numbers of codes.

中间件大部分时间都在妨碍;每次定义路由时,都必须编写尽可能多的代码。

Hapi would be the best choice for a developer looking to build RESTful API. Hapi has micro-service architecture and it is also possible to transfer the control from one handler to another based on certain parameters. With the Hapi plugin, you can enjoy a greater level of abstraction around HTTP because you can divvy up the business logic into pieces easily manageable.

Hapi 将是希望构建 RESTful API 的开发人员的最佳选择。Hapi 具有微服务架构,还可以根据某些参数将控制权从一个处理程序转移到另一个处理程序。使用 Hapi 插件,您可以享受更高级别的 HTTP 抽象,因为您可以将业务逻辑分成易于管理的部分。

Another huge advantage with Hapi is that it provides detailed error messages when you misconfigure. Hapi also lets you configure your file upload size by default. If the maximum upload size is limited, you can send an error message to the user conveying that the file size is too large. This would protect your server from crashing because the file uploads will no longer try to buffer a whole file.

Hapi 的另一个巨大优势是,当您配置错误时,它会提供详细的错误消息。默认情况下,Hapi 还允许您配置文件上传大小。如果最大上传大小受到限制,您可以向用户发送错误消息,告知文件大小过大。这将保护您的服务器免于崩溃,因为文件上传将不再尝试缓冲整个文件。

  1. Whatever you can achieve using express can also be easily achieved using hapi.js.

  2. Hapi.js is very stylish and organizes the code very well. If you see how it does routing and puts the core logic in controllers you will defiantly be going to love it.

  3. Hapi.js officially provide several plugins exclusively for hapi.js ranges from token based auth to session management and many more, which is an ad on. It doesn't mean the traditional npm can't be used, all of them are supported by hapi.js

  4. If you code in hapi.js, a code would be very maintainable.

  1. 使用 express 可以实现的任何内容也可以使用 hapi.js 轻松实现。

  2. Hapi.js 非常时尚,代码组织得很好。如果您看到它如何进行路由并将核心逻辑置于控制器中,您一定会爱上它。

  3. Hapi.js 官方提供了几个专门用于 hapi.js 的插件,范围从基于令牌的身份验证到会话管理等等,这是一个广告。不是说传统的npm不能用,hapi.js都支持

  4. 如果您在 hapi.js 中编写代码,那么代码将非常易于维护。

回答by Peter

I've started using Hapi recently and I'm quite happy with it. My reasons are

我最近开始使用 Hapi,我对它很满意。我的理由是

  1. Easier to test. For example:

    • server.injectallows you to run the app and get a response without it running and listening.
    • server.infogives the current uri, port etc.
    • server.settingsaccesses the configuration e.g. server.settings.cachegets current cache provider
    • when in doubt look at the /testfolders for any part of the app or supported plugins to see suggestions on how to mock/test/stub etc.
    • my sense is that the architectural model of hapi allows you to trust but verify e.g. Are my plugins registered? How can I declare a module dependency?
  2. It works out of the box e.g. file uploads, return streams from endpoints etc.

  3. Essential plugins are maintained along with the core library. e.g template parsing, cachingetc. The added benefit is the same coding standards are applied across the essential things.

  4. Sane errors and error handling. Hapi validates config optionsand keeps an internal route table to prevent duplicate routes. This is quite useful while learning because errors are thrown early instead of unexpected behaviours which require debugging.

  1. 更容易测试。例如:

    • server.inject允许您运行应用程序并在不运行和监听的情况下获得响应。
    • server.info给出当前的 uri、端口等。
    • server.settings访问配置,例如server.settings.cache获取当前缓存提供者
    • 如有疑问/test,请查看应用程序任何部分或支持的插件的文件夹,以查看有关如何模拟/测试/存根等的建议。
    • 我的感觉是 hapi 的架构模型允许您信任但验证例如我的插件是否已注册?如何声明模块依赖项
  2. 它开箱即用,例如文件上传,从端点返回流等。

  3. 基本插件与核心库一起维护。例如模板解析缓存等。额外的好处是相同的编码标准应用于基本事物。

  4. 理智的错误和错误处理。Hapi验证配置选项并保留内部路由表以防止重复路由。这在学习时非常有用,因为错误会提前抛出,而不是需要调试的意外行为。

回答by UchihaItachi

Just another point to add, Hapi has started supporting 'http2' calls from version 16 onwards (if I am not wrong ). However, express is yet to support 'http2' module directly till express 4. Although they have released the feature in the alpha version of express 5.

再补充一点,Hapi 从 16 版开始支持“http2”调用(如果我没记错的话)。但是,express 直到 express 4 还没有直接支持 'http2' 模块。虽然他们已经在 express 5 的 alpha 版本中发布了该功能。

回答by alberdo dellagiacoma

'use strict';
const Hapi = require('hapi');
const Basic = require('hapi-auth-basic');
const server = new Hapi.Server();
server.connection({
    port: 2090,
    host: 'localhost'
});


var vorpal = require('vorpal')();
const chalk = vorpal.chalk;
var fs = require("fs");

var utenti = [{
        name: 'a',
        pass: 'b'
    },
    {
        name: 'c',
        pass: 'd'
    }
];

const users = {
    john: {
        username: 'john',
        password: 'secret',
        name: 'John Doe',
        id: '2133d32a'
    },
    paul: {
        username: 'paul',
        password: 'password',
        name: 'Paul Newman',
        id: '2133d32b'
    }
};

var messaggi = [{
        destinazione: 'a',
        sorgente: 'c',
        messsaggio: 'ciao'
    },
    {
        destinazione: 'a',
        sorgente: 'c',
        messsaggio: 'addio'
    },
    {
        destinazione: 'c',
        sorgente: 'a',
        messsaggio: 'arrivederci'
    }
];

var login = '';
var loggato = false;

vorpal
    .command('login <name> <pass>')
    .description('Effettua il login al sistema')
    .action(function (args, callback) {
        loggato = false;
        utenti.forEach(element => {
            if ((element.name == args.name) && (element.pass == args.pass)) {
                loggato = true;
                login = args.name;
                console.log("Accesso effettuato");
            }
        });
        if (!loggato)
            console.log("Login e Password errati");
        callback();
    });

vorpal
    .command('leggi')
    .description('Leggi i messaggi ricevuti')
    .action(function (args, callback) {
        if (loggato) {
            var estratti = messaggi.filter(function (element) {
                return element.destinazione == login;
            });

            estratti.forEach(element => {
                console.log("mittente : " + element.sorgente);
                console.log(chalk.red(element.messsaggio));
            });
        } else {
            console.log("Devi prima loggarti");
        }
        callback();
    });

vorpal
    .command('invia <dest> "<messaggio>"')
    .description('Invia un messaggio ad un altro utente')
    .action(function (args, callback) {
        if (loggato) {
            var trovato = utenti.find(function (element) {
                return element.name == args.dest;
            });
            if (trovato != undefined) {
                messaggi.push({
                    destinazione: args.dest,
                    sorgente: login,
                    messsaggio: args.messaggio
                });
                console.log(messaggi);
            }
        } else {
            console.log("Devi prima loggarti");
        }
        callback();
    });

vorpal
    .command('crea <login> <pass>')
    .description('Crea un nuovo utente')
    .action(function (args, callback) {
        var trovato = utenti.find(function (element) {
            return element.name == args.login;
        });
        if (trovato == undefined) {
            utenti.push({
                name: args.login,
                pass: args.pass
            });
            console.log(utenti);
        }
        callback();
    });

vorpal
    .command('file leggi utenti')
    .description('Legge il file utenti')
    .action(function (args, callback) {
        var contents = fs.readFileSync("utenti.json");
        utenti = JSON.parse(contents);
        callback();
    });

vorpal
    .command('file scrivi utenti')
    .description('Scrive il file utenti')
    .action(function (args, callback) {
        var jsontostring = JSON.stringify(utenti);
        fs.writeFile('utenti.json', jsontostring, function (err) {
            if (err) {
                return console.error(err);
            }
        });
        callback();
    });

vorpal
    .command('file leggi messaggi')
    .description('Legge il file messaggi')
    .action(function (args, callback) {
        var contents = fs.readFileSync("messaggi.json");
        messaggi = JSON.parse(contents);
        callback();
    });

vorpal
    .command('file scrivi messaggi')
    .description('Scrive il file messaggi')
    .action(function (args, callback) {
        var jsontostring = JSON.stringify(messaggi);
        fs.writeFile('messaggi.json', jsontostring, function (err) {
            if (err) {
                return console.error(err);
            }
        });
        callback();
    });

// leggi file , scrivi file

vorpal
    .delimiter(chalk.yellow('messaggi$'))
    .show();




const validate = function (request, username, password, callback) {
    loggato = false;


    utenti.forEach(element => {
        if ((element.name == username) && (element.pass == password)) {
            loggato = true;
            console.log("Accesso effettuato");
            return callback(null, true, {
                name: username
            })
        }
    });
    if (!loggato)
        return callback(null, false);
};

server.register(Basic, function (err) {
    if (err) {
        throw err;
    }
});

server.auth.strategy('simple', 'basic', {
    validateFunc: validate
});



server.route({
    method: 'GET',
    path: '/',
    config: {
        auth: 'simple',
        handler: function (request, reply) {
            reply('hello, ' + request.auth.credentials.name);
        }
    }
});

//route scrivere
server.route({
    method: 'POST',
    path: '/invia',
    config: {
        auth: 'simple',
        handler: function (request, reply) {
            //console.log("Received POST from " + request.payload.name + "; id=" + (request.payload.id || 'anon'));
            var payload = encodeURIComponent(request.payload)
            console.log(request.payload);
            console.log(request.payload.dest);
            console.log(request.payload.messaggio);
            messaggi.push({
                destinazione: request.payload.dest,
                sorgente: request.auth.credentials.name,
                messsaggio: request.payload.messaggio
            });
            var jsontostring = JSON.stringify(messaggi);
            fs.writeFile('messaggi.json', jsontostring, function (err) {
                if (err) {
                    return console.error(err);
                }
            });
            console.log(messaggi);
            reply(messaggi[messaggi.length - 1]);

        }
    }
});


//route leggere (json)
server.route({
    method: 'GET',
    path: '/messaggi',
    config: {
        auth: 'simple',
        handler: function (request, reply) {
            messaggi = fs.readFileSync("messaggi.json");
            var estratti = messaggi.filter(function (element) {
                return element.destinazione == request.auth.credentials.name;
            });
            var s = [];

            console.log(request.auth.credentials.name);
            console.log(estratti.length);
            estratti.forEach(element => {

                s.push(element);

                //fare l'array con stringify
                //s+="mittente : "+element.sorgente+": "+element.messsaggio+"\n";

            });
            var a = JSON.stringify(s);
            console.log(a);
            console.log(s);
            reply(a);
        }
    }
});



server.start(function () {
    console.log('Hapi is listening to ' + server.info.uri);
});

function EseguiSql(connection, sql, reply) {
    var rows = [];
    request = new Request(sql, function (err, rowCount) {
        if (err) {
            console.log(err);
        } else {
            console.log(rowCount + ' rows');
            console.log("Invio Reply")
            reply(rows);
        }
    });

    request.on('row', function (columns) {
        var row = {};
        columns.forEach(function (column) {
            row[column.metadata.colName] = column.value;
        });
        rows.push(row);
    });

    connection.execSql(request);
}

server.route({
    method: 'POST',
    path: '/query',
    handler: function (request, reply) {
        // Qui dovrebbe cercare i dati nel body e rispondere con la query eseguita
        var connection = new Connection(config);

        // Attempt to connect and execute queries if connection goes through
        connection.on('connect', function (err) {
            if (err) {
                console.log(err);
            } else {

                console.log('Connected');
                console.log(request.payload.sql);
                EseguiSql(connection, request.payload.sql, reply);
            }
        });

    }
});

server.connection({
    host: process.env.HOST || 'localhost',
    port: process.env.PORT || 8080
});

var config = {
    userName: process.env.DB_USER,
    password: process.env.DB_PASSWORD,
    server: process.env.DB_SERVER,
    options: {
        database: process.env.DB_NAME,
        encrypt: true
    }
}

回答by alberdo dellagiacoma

    const Hapi = require('hapi');
var Connection = require('tedious').Connection;
var Request = require('tedious').Request;
var TYPES = require('tedious').TYPES;
const server = new Hapi.Server();
var vorpal = require('vorpal')();

server.connection({
    host: process.env.HOST || 'localhost',
    port: process.env.PORT || 3000
});
server.start(function (err) {
    if (err) {
        throw err;
    }
    console.log("server running at : " + server.info.uri);
});

var config =
{
    userName: 'sa',
    password: 'password.123',
    server: 'localhost',

    options:
    {
        database: '',
        port: 1433
    }
}

server.route(
    {
        method: 'GET',
        path: '/{categoria}',
        handler: function (request, reply) {
            var connection = new Connection(config);
            connection.on('connect', function (err) {
                if (err) {
                    console.log(err);
                }
                else {
                    console.log('Connected');
                    EseguiSqlGet(connection, request.params.categoria, reply);
                }
            });
        }
    }
);
function EseguiSqlGet(connection, cat, reply) {
    var rows = [];
    var sql = 'SELECT * FROM Prodotti INNER JOIN Categorie
 on Categorie.IdCategoria = Prodotti.IdCategoria
 WHERE Categorie.IdCategoria = ' + cat ;
    request_sql = new Request(sql, function(err, rowCount) {
        if (err) {
            console.log(err);
        } else {
            console.log(rowCount + ' rows');
            console.log("Invio Reply")
            reply(rows);
        }
    });

    request_sql.on('row', function(columns) {
        var row = {};
        columns.forEach(function (column) {
            row[column.metadata.colName] = column.value;
        });
        rows.push(row);
    });

    connection.execSql(request_sql);
}
// POST
server.route(
    {
        method: 'POST',
        path: '/inserisci',
        handler: function (request, reply) {
            var connection = new Connection(config);
            connection.on('connect', function (err) {
                if (err) {
                    console.log(err);
                }
                else {
                    console.log('Connected');
                    EseguiSqlPost(connection,reply, 
request.payload.idcat, request.payload.nome, request.payload.prezzo );
                }
            });
        }
    }
);
function EseguiSqlPost(connection,reply, cat,nome,prezzo) {

    var sql = "INSERT INTO Prodotti
 VALUES("+ cat +",'"+nome+"',"+prezzo+")";
    request_sql = new Request(sql, function(err, rowCount) {
        if (err) {
            console.log(err);
        } else {
            console.log(rowCount + ' rows');
            console.log("Invio Reply")
            reply('riga aggiunta');
        }
    });

    /*request_sql.on('row', function(columns) {
        var row = {};
        columns.forEach(function (column) {
            row[column.metadata.colName] = column.value;
        });
        rows.push(row);
    });
*/
    connection.execSql(request_sql);
}






//VORPAL COMMAND PROMT
var categoria = [
    {

        'idcategoria':'1',
        'nome':'ciao',

    }
]


vorpal
    .command('inserisci <categoria> <nome>')
    .action(function(args, callback)
    {
        categoria.push(   
{'idcategoria':args.categoria,'nome':args.nome}     );
        console.log(JSON.stringify(categoria));
        callback();
    });

vorpal
.delimiter("delimeter")
.show();