Express.js 与 Nest.js对比

Express.js 与 Nest.js对比

自从 Node.js 发布以来,Javascript 在后端领域的使用有所增加。由于 Node.js 的使用越来越多,每天都会有新的框架和工具发布。ExpressNest 是使用 Node.js 创建后端应用程序的最著名的框架之一,在本文中,我们将对它们进行比较。

Express

ExpressNode.js 的简约框架。尽管它涵盖了创建服务器端应用程序的几个核心方面,但由于其简单性、灵活性和性能,它很流行,甚至 Nest 也是构建在 Express 之上的。但是,express 仍然存在一些问题,在我们深入研究这些问题之前,我们需要了解它们为我们提供了什么,让我们不使用任何框架而仅使用 Node.js 创建一个 Web 服务器。

const http = require("node:http");// Create a local server to receive data from
const server = http.createServer((req, res) => {res.writeHead(200, { "Content-Type": "application/json" });res.end(JSON.stringify({ message: "Hello World!" }));
});server.listen(8000);

在上面的代码中,我们使用 Node.js 中内置的 HTTP 模块创建一个 Web 服务器。如果我们向http://localhost:8000发送 Web 请求,将从我们的 Node.js 服务器收到一条消息 (Hello World)。

这很简单,但是如果我们想创建一个包含数百条不同路由的 REST API 该怎么办?然后我们必须编写一个路由匹配器并将每个路由发送到其特定的控制器。另外,我们必须实现 GETPOSTPUTHTTP 方法来满足 REST 标准,对吗?Express 所做的正是这个,express 为我们处理请求/响应控制、路由、提供静态文件和中间件。这就是 Express 如此轻量和简单的美妙之处。现在让我们看看如何使用express 创建之前的应用程序。

const express = require("express");
const app = express();app.get("/", (req, res) => {res.send({ message: "Hello World" });
});app.listen(8000);

上面的代码也做了同样的事情。但是express为我们提供了一个与请求的URL匹配的路由机制,所以如果我们想使用express router创建一个cat路由,它会看起来像这样。

const express = require("express");
const app = express();
const router = express.Router();router.get("/", (req, res) => {res.send("Hello Cats");
});router.post("/create", (req, res) => {res.send("Create New Cat!");
});app.use("/cats", router);
app.listen(8000);

这很好,但是Express有什么问题呢?Express 非常简约且直接,为用户提供了灵活性。灵活性对于有经验的用户或复杂的场景非常有利,但灵活性会导致错误和结构错误的增加。此外,现在的应用程序需要大量额外的逻辑,例如请求验证、授权、文档、测试、日志记录等。因此,Express 只为我们提供了一些功能,人们需要使用其他库或框架来解决这些需求。这就是 Nest.js 存在的原因。

Nest

Nest 是一个用于构建高效、可扩展的 Node.js 服务器端应用程序的框架。Nest 构建在常见 Node.js 框架(ExpressFastify)之上。它使用渐进式 JavaScript,使用 TypeScript 构建并完全支持 TypeScript(但仍然允许开发人员使用纯 JavaScript 进行编码),并结合了 OOP(面向对象编程)、FP(函数式编程)和 FRP(函数式反应式编程)的元素。

Nest 在这些常见 Node.js 框架(Express/Fastify)之上提供抽象,并将其 API 直接公开给开发人员。这使开发人员可以自由地使用可用于底层平台的无数第三方模块。Nest 的目的是创建高度可测试、可扩展、松散耦合且易于维护的应用程序。

为了证明这一点,让我们使用 Nest 重构之前的应用:

import { Controller, Get, Post } from '@nestjs/common';
@Controller('cat')
export class CatController {@Get()getCats() {return 'Hello World';}@Post('create')create() {return 'Create New Cat!';}
}

Nest 的路由方法与控制器配合使用,控制器可以组织路由并使路由更清晰、更易于管理。Nest 有一个默认的错误处理程序和其他内置实用程序,可帮助我们快速入门。当然,可以用express手动实现它们,但不需要重新发明轮子。所有这些便利设置使 Nest 成为初学者的更好选择,因为这些核心实用程序对于初学者来说可能很难理解。

对比

现在我们了解了这些框架的基础知识,让我们深入了解、对比一下ExpressNext

1. 架构

Express 中,没有架构标准。这在许多大型项目或微服务应用程序中成为一个问题,因为它们需要强大而灵活的架构来保持应用程序的可维护性。

另一方面,Nest 最强大的一面是架构,因为 Nest 有许多实用程序来提供灵活、干净且​​强大的架构。Nest-Modules 就是一个很好的例子。Nest-Module 用于组织应用程序结构并帮助开发人员管理模块的依赖关系。

Nest 还非常适合应用 N 层架构,旨在将应用程序划分为逻辑层。层是一种分离职责和管理依赖关系以实现关注点分离 (SoC) 原则的方法。为了实现这一目标,Nest 建议调用控制器内的服务层,并在这些服务层内执行所有业务逻辑。对于服务层,调用另一个层称为存储库层,该层负责数据访问。因此,我们将我们的关注点分为三层。分离这些层可以为软件提供可重用性和可维护性。它还使我们的应用程序易于测试,

我们创建的cat路由,它可能看起来像这样:

CatController -> CatService -> CatRepository

在这里插入图片描述
因此,每当我们需要在任何控制器中调用 CatService 的方法时,我们只需创建 CatService 的实例并调用该方法,或者我们可以通过将 CatService 实例作为 CatController 构造函数的参数传递来使用现有的 CatService 实例,即Nest还有一个概念叫做依赖注入。

2. 依赖注入

依赖注入是一种设计模式,其中一个对象接收它所依赖的其他对象。依赖注入是控制反转的一种形式,旨在分离构造对象和使用对象的关注点,从而导致松散耦合的程序。

Nest 中,可以通过在要注入的模块顶部添加 Injectable 装饰器来使用依赖注入。例如

import { Injectable } from '@nestjs/common';
@Injectable()
export class CatService {findAll() {return 'Hello World';}create() {return 'Create New Cat!';}
}
import { Controller, Get, Post } from '@nestjs/common';
import { CatService } from './cat.service';@Controller('cat')
export class CatController {constructor(private readonly catService: CatService) {}@Get()getCats() {return this.catService.findAll();}@Post('create')create() {return this.catService.create();}
}

正如我们所看到的,我们将 catService 实例作为参数传递给 CatController 的构造函数。这种方法使应用程序更易于维护且易于测试,尤其是对于大型应用程序。这是使用 Nest 的最大优势之一。

3. 中间件

默认情况下,Nest 中间件相当于 Express 中间件。在 Express 中间件中,我们只需创建另一个在控制器之前/之后运行的路由处理程序。Nest 有一个MiddlewareConsumer类,它是一个辅助类。它提供了几种内置方法来管理中间件。所有这些都可以简单地以流畅的方式链接起来。MiddlewareConsumer 有一个forRoutes属性,我们可以在其中简单地输入字符串或控制器的路径来注册中间件。Nest 还有一个exclude属性,可以帮助我们排除路径或控制器。

Nest 还提供类似中间件的实用程序,例如管道、过滤器和拦截器。它们可以被认为是中间件,但它们更专注于不同的目的。例如,管道主要用于验证和数据转换。另一方面,中间件是在路由处理程序之前运行的处理程序,并且可以访问请求对象。过滤器与中间件相反。它们在路由处理程序之后运行并操作响应对象以进行错误处理等。最后,拦截器可以在调用路由处理程序之前和之后访问请求和响应对象。

Nest 还提供了一个名为 ExecutionContext 的实用程序,它提供有关当前执行过程的其他详细信息,例如接下来要执行的内容,而 Express 中间件则缺少此信息。

4. 自定义异常

Nest 为大多数场景提供了默认的异常类,例如 NotFoundExceptionUnAuthorizedException 等。这可以节省我们一些时间。此外,还可以像在express中一样创建自己的异常类。

5. 验证

请求验证在很多方面都是有益的。它可以防止错误发生,并向用户显示一条有意义的消息,表明他们发送了错误的输入。此外,它还可以防止用户发送不需要的输入,从而使应用程序更加安全。

express中,我曾经在处理程序之前添加一个中间件,这个中间件采用一个验证器作为参数,该验证器是使用Joi工具创建的。但这非常耗时,并且会导致我们的路由/处理程序声明看起来更长、更复杂,并且有时候会忘记在处理程序之前添加验证器。不可能创建可在整个应用程序的所有上下文中使用的通用中间件。这是因为中间件不知道执行上下文,包括将被调用的处理程序及其任何参数。

6. 授权

授权是后端应用程序中的常见需求。某些服务可能需要基于角色的授权以防止不允许的操作。授权通常由传统 Express 应用程序中的中间件处理,通常看起来像这样。

router.get('/create', authorize(Role.Admin), create);

Nest 的授权方式类似,但 Nest 通过其Guards概念提供了一些便利。守卫确定给定的请求是否将由路由处理程序处理。防护可以是控制器范围、方法范围或全局范围,这在实现中提供了易用性,也有助于保持代码干燥和声明性。此外,执行上下文可用于构建通用防护,这使得防护比传统中间件更强大。

@Post() 
@Roles('admin') 
async create(@Body() createCatDto: CreateCatDto) { this.catsService.create(createCatDto); 
}

7. 数据库

express中我们通常使用 ORM(对象关系映射器)或ODM(对象文档映射器)如SequelizeMongoose 来处理数据库操作。Nest 没有什么不同,但 Nest 具有内置的 ORM-ODM 工具,这些工具提供模型/存储库注入、可测试性和动态配置,以便访问我们选择的数据库,我认为,Nest 的架构使使用数据库变得更容易

8.API文档

迄今为止,在 Nest.js 中记录 API 是最简单的。Nest 提供了一个 swagger 模块,可以自动为 API 端点创建文档。此外,还可以使用如下装饰器定义请求/响应模式。

  @ApiBody({ type: CreateCatDto })@ApiCreatedResponse({ type: CreateCatResponseDto })create(@Body() createSampleDto: CreateCatDto) : CreateCatResponseDto{// ...}

9. 性能

Nest 允许使用 Fastify 适配器,它比 Express 适配器快两倍,如果不使用 Fastify 适配器,Nest 将无法击败 Express。我们知道 Nest 提供了这两个适配器的抽象以在它们之间进行切换,但这在每种情况下都是不可能的,因为在某些情况下这两个适配器的行为本质上不同。例如,fastify 适配器不支持嵌套路由,因此应该使用 Express 适配器来实现这一点。

10. 测试

Nest 最强大的架构优势也在这里获胜。正如我们之前讨论的那样,Nest 使用模块并将它们与依赖项注入结合起来,这允许将任何依赖项注入到任何模块,因此我们可以注入测试服务而无需实例化它,并且它可以节省大量时间和精力,特别是对于较大的模块和服务。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/196610.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

JVM判断对象是否存活之引用计数法、可达性分析

目录 前言 引用计数法 概念 优点 缺点 可达性分析 概念 缺点: 扩展: 1.GC Roots 概念 2.STW (Stop the world) 前言 JVM有两种算法来判断对象是否存活,分别是引用计数法和可达性分析算法,针对可达性分析算法STW时间长、…

阿里AoneFlow分支管理

分支模式 1.TrunkBased模式 工作方式 TrunkBased 模式是持续集成思想所崇尚的工作方式,它由单个主干分支和许多发布分支组成,每个发布分支在特定版本的提交点上从主干创建出来,用来进行上线部署和 Hotfix(补丁)。 …

workman使用手册1.0

workman官网地址:高性能PHP应用容器 workerman 1:把workman项目放到linux服务器后,需要启动你的php文件,才可以使用 定位到项目根目录:例:cd /mnt/workman 启动代码:php outin.php start -d 停…

Python小白之PyCharm仍然显示“No module named ‘xlwings‘”

Python小白之“没有名称为xlwings‘的模块”-CSDN博客文章浏览阅读8次。cmd 打开命令行,输入python出现>>>的提示格,输入import xlwings 回车,正常报错:No module named xlwings。输入python 回车后,再输入im…

mongodb使用简单文档

1、mongodb安装与卸载 1.1、安装 python -m pip install pymongo 或 pip install pymongo如果要安装指定版本: python -m pip install pymongo3.5.1对已有的版本进行升级: python -m pip install --upgrade pymongo1.2、卸载 pip uninstall pymongo…

环境配置 | Git的安装及配置[图文详情]

Git是一个开源的分布式版本控制系统,可以有效、高速地处理从小到大的项目版本管理。下面介绍了基础概念及详细的用图文形式介绍一下git安装过程. 目录 1.Git基础概念 2.Git的下载及安装 3.常见的git命令 Git高级技巧 Git与团队协作 1.Git基础概念 仓库&#…

我认为除了HelloWorld之外,Python的三大数据转换实例可以作为开始学习Python的入门语言。

Python的三大数据转换实例 一、反转三位数 class Solution:def funtcion(self,number):hint(number/100)tint(number%100/10)zint(number%10)return 100*z10*th if __name____main__:solution Solution()num123new_num solution.funtcion(num)print("输入:{}".fo…

制作Go程序的Docker容器

今天突然遇到需要将 Go 程序制作成 Docker 的需求,所以进行了一些研究。方法很简单,但是官方文档和教程有些需要注意的地方,所以写本文进行记录。 源程序 首先介绍一下示例程序,示例程序是一个 HTTP 服务器,会显示si…

基于DOTween插件实现金币飞行到指定位置功能

文章目录 前言一、DOTween是什么?二、使用步骤1.导入DOTween插件在Unity官方插件商店找到DOTween插件导入DOTween插件启用DOTween插件 2.代码逻辑金币飞行代码控制飞行效果代码 3.物体配置1.物体上装配CoinEffect脚本2.在金币预制体上装配FlyControl脚本 三、效果展…

基于SpringBoot的SSMP整合案例(消息一致性处理与表现层开发)

消息一致性处理 在后端执行完相应的操作后,我们需要将执行操作后的结果与数据返回前端,前端 调用我们传回去的数据,前端是如何知道我们传回去的数据名称的? 答:前后端遵循了同一个"协议"。这个协议就是定义…

单例模式(常用)

单例模式(单例设计模式) 在有些系统中,为了节省内存资源、保证数据内容的一致性,对某些类要求只能创建一个实例,这就是所谓的单例模式。 单例模式的定义与特点 单例(Singleton)模式的定义:指…

Stable Diffusion1.5网络结构-超详细原创

目录 1 Unet 1.1详细整体结构 1.2 缩小版整体结构 1.3 时间步编码 1.4 CrossAttnDownBlock2D 1.4.1 ResnetBlock2D 1.4.2 Transformer2DModel 1.4.2.1 BasicTransformerBlock 1.4.2.1.1 SelfAttention 1.4.2.1.2 CrossAttention 1.4.2.1.3 FeedForward 1.4.3 DownS…

【数据库】数据库连接池导致系统吞吐量上不去-复盘

在实际的开发中,我们会使用数据库连接池,但是如果不能很好的理解其中的含义,那么就可以出现生产事故。 HikariPool-1 - Connection is not available, request timed out after 30001ms.当系统的调用量上去,就出现大量这样的连接…

Git 基本操作

目录 创建仓库命令 git init git clone 提交与修改 git add git status git diff git commit git reset git rm git mv git checkout git switch git restore 提交日志 git log git blame 远程操作 git remote git fetch git pull git push Git 的工作就…

Redis维护缓存的方案选择

Redis中间件常常被用作缓存,而当使用了缓存的时候,缓存中数据的维护,往往是需要重点关注的,尤其是重点考虑的是数据一致性问题。以下是维护数据库缓存的一些常用方案。 1、先删除缓存,再更新数据库 导致数据不一致的…

如何实现Redisson分布式锁

首先,不要将分布式锁想的太复杂,如果我们只是平时业务中去使用,其实不算难,但是很多人写的文章不能让人快速上手,接下来,一起看下Redisson分布式锁的快速实现 Redisson 是一个在 Redis 的基础上实现的 Java…

机器学习第4天:模型优化方法—梯度下降

文章目录 前言 梯度下降原理简述 介绍 可能的问题 批量梯度下降 随机梯度下降 基本算法 存在的问题 退火算法 代码演示 小批量梯度下降 前言 若没有机器学习基础,建议先阅读同一系列以下文章 机器学习第1天:概念与体系漫游-CSDN博客 机器学习…

802.11-2020协议学习__专题__TxTime-Calculation__HR/DSSS

802.11-2020协议学习__专题__TxTime-Calculation__HR/DSSS 16.2.2 PPDU format16.2.2.1 General16.2.2.2 Long PPDU format16.2.2.3 Short PPDU format 16.3.4 HR/DSSS TXTIME calculation PREV: TBD NEXT: TBD 16.2.2 PPDU format 16.2.2.1 General 定…

五分钟,Docker安装kafka 3.5,kafka-map图形化管理工具

首先确保已经安装docker,如果是windows安装docker,可参考 wsl2安装docker 1、安装zk docker run -d --restartalways -e ALLOW_ANONYMOUS_LOGINyes --log-driver json-file --log-opt max-size100m --log-opt max-file2 --name zookeeper -p 2181:218…