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 different routing 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 article about 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需要更多的配置才能获得相同的功能。
2 个解决方案
#1
194
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 http
module alone. The http
module can do everything we want but it's tedious to write applications with.
这两个框架都解决了相同的基本问题:为在node中构建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-type
header to check which it is and parse it accordingly (form-data vs JSON vs multi-part for example), often using separate modules.
快递的目标是非常小的。通过向您提供一个小的API,在http之上只进行少量的除尘,您仍然可以自己添加额外的功能。如果您想读取传入请求的主体(相当常见的任务),您需要安装一个单独的模块。如果您希望将各种内容类型发送到该路由,您还需要检查内容类型头以检查它是什么,并相应地解析它(例如表单-数据vs JSON vs JSON多部分),通常使用单独的模块。
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不具备的一些内置特性(据我所知):
- Input and response validation (through Joi)
- 输入和响应验证(通过Joi)
- Server-side caching with multiple storage options (mongo, S3, redis, riak), that can be enabled with a few lines of configuration
- 具有多个存储选项(mongo、S3、redis、riak)的服务器端缓存,只需几行配置即可启用
- Cookie-parsing
- Cookie-parsing
- Sessions
- 会话
- File uploading/multipart parsing
- 文件上传/多部分解析
- CORS support
- 歌珥支持
- Logging
- 日志记录
Extensibility & modularity
hapi and Express go about extensibility in quite a different way. With Express, you have middleware functions. 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 lifecycle and 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 system in 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.
一个插件就像一个子应用程序,你可以做任何事你可以在一个哈皮神应用,增加航线,扩展点在一个插件等。可以肯定的是,你没有打破另一个应用程序的一部分,因为注册的顺序路线并不重要,你不能创建冲突的路线。然后,您可以将这个插件合并到服务器中并部署它。
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是由沃尔玛负责管理黑色星期五交通的团队设计的,因此安全与稳定一直是人们最关心的问题。由于这个原因,框架做了很多额外的事情,比如限制传入的有效负载大小,以防止耗尽进程内存。它还有一些选项,比如max事件循环延迟、使用的max 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 hapi and the above is largely my personal opinion.
免责声明:作为一本关于hapi的书的作者,我有偏见,以上大部分都是我的个人观点。
#2
46
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.
- 由主要的陆战队。这意味着社区的支持将是强大的,并且在以后的版本中对您都是如此。很容易找到充满激情的Hapi人员,那里有很好的教程(虽然没有像ExpressJs教程那么多,那么杂乱)。在此发布日期,npm和沃尔玛使用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).
- 它可以促进分布式团队处理后端服务的各个部分的工作,而不必对API表面的其他部分有全面的了解(Hapi的插件体系结构就是这种质量的缩影)。
- 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一年之后,我肯定觉得Hapi完成了这个。我…感觉快乐!
If you want to hear directly from Eran Hammer (Hapi's lead)
如果你想直接从Eran Hammer听到(Hapi’s lead)
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没有同样的“明星力量”……但是一旦你感到舒适,你就会得到很多里程。我花了大约2个月的时间成为一个不负责任使用ExpressJs的黑客。如果您是一个经验丰富的后端开发人员,您将知道如何阅读文档,您甚至可能不会注意到这一点。
Areas the Hapi documentation can improve on:
Hapi文档可以改进的地方:
- how to authenticate users and create sessions
- 如何对用户进行身份验证并创建会话
- handling Cross-Origin-Requests (CORS)
- 处理Cross-Origin-Requests(歌珥)
- uploading files (multipart, chunked)
- 上传文件(扇形,分块)
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.
剩下的两个其实没那么难,文档可以写得更好一点。
#1
194
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 http
module alone. The http
module can do everything we want but it's tedious to write applications with.
这两个框架都解决了相同的基本问题:为在node中构建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-type
header to check which it is and parse it accordingly (form-data vs JSON vs multi-part for example), often using separate modules.
快递的目标是非常小的。通过向您提供一个小的API,在http之上只进行少量的除尘,您仍然可以自己添加额外的功能。如果您想读取传入请求的主体(相当常见的任务),您需要安装一个单独的模块。如果您希望将各种内容类型发送到该路由,您还需要检查内容类型头以检查它是什么,并相应地解析它(例如表单-数据vs JSON vs JSON多部分),通常使用单独的模块。
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不具备的一些内置特性(据我所知):
- Input and response validation (through Joi)
- 输入和响应验证(通过Joi)
- Server-side caching with multiple storage options (mongo, S3, redis, riak), that can be enabled with a few lines of configuration
- 具有多个存储选项(mongo、S3、redis、riak)的服务器端缓存,只需几行配置即可启用
- Cookie-parsing
- Cookie-parsing
- Sessions
- 会话
- File uploading/multipart parsing
- 文件上传/多部分解析
- CORS support
- 歌珥支持
- Logging
- 日志记录
Extensibility & modularity
hapi and Express go about extensibility in quite a different way. With Express, you have middleware functions. 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 lifecycle and 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 system in 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.
一个插件就像一个子应用程序,你可以做任何事你可以在一个哈皮神应用,增加航线,扩展点在一个插件等。可以肯定的是,你没有打破另一个应用程序的一部分,因为注册的顺序路线并不重要,你不能创建冲突的路线。然后,您可以将这个插件合并到服务器中并部署它。
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是由沃尔玛负责管理黑色星期五交通的团队设计的,因此安全与稳定一直是人们最关心的问题。由于这个原因,框架做了很多额外的事情,比如限制传入的有效负载大小,以防止耗尽进程内存。它还有一些选项,比如max事件循环延迟、使用的max 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 hapi and the above is largely my personal opinion.
免责声明:作为一本关于hapi的书的作者,我有偏见,以上大部分都是我的个人观点。
#2
46
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.
- 由主要的陆战队。这意味着社区的支持将是强大的,并且在以后的版本中对您都是如此。很容易找到充满激情的Hapi人员,那里有很好的教程(虽然没有像ExpressJs教程那么多,那么杂乱)。在此发布日期,npm和沃尔玛使用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).
- 它可以促进分布式团队处理后端服务的各个部分的工作,而不必对API表面的其他部分有全面的了解(Hapi的插件体系结构就是这种质量的缩影)。
- 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一年之后,我肯定觉得Hapi完成了这个。我…感觉快乐!
If you want to hear directly from Eran Hammer (Hapi's lead)
如果你想直接从Eran Hammer听到(Hapi’s lead)
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没有同样的“明星力量”……但是一旦你感到舒适,你就会得到很多里程。我花了大约2个月的时间成为一个不负责任使用ExpressJs的黑客。如果您是一个经验丰富的后端开发人员,您将知道如何阅读文档,您甚至可能不会注意到这一点。
Areas the Hapi documentation can improve on:
Hapi文档可以改进的地方:
- how to authenticate users and create sessions
- 如何对用户进行身份验证并创建会话
- handling Cross-Origin-Requests (CORS)
- 处理Cross-Origin-Requests(歌珥)
- uploading files (multipart, chunked)
- 上传文件(扇形,分块)
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.
剩下的两个其实没那么难,文档可以写得更好一点。