当前位置: 首页 > news >正文

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 使用模块并将它们与依赖项注入结合起来,这允许将任何依赖项注入到任何模块,因此我们可以注入测试服务而无需实例化它,并且它可以节省大量时间和精力,特别是对于较大的模块和服务。

相关文章:

Express.js 与 Nest.js对比

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

总结 CNN 模型:将焦点转移到基于注意力的架构

一、说明 在计算机视觉时代,卷积神经网络(CNN)几十年来一直是主导范式。直到 2021 年 Vision Transformers (ViTs) 出现,这个领域才开始发生变化。现在,是时候采用受 Transformer 架构启发的基于注意力的模型了&#x…...

2023.11.16 hivesql高阶函数之开窗函数

目录 1.开窗函数的定义 2.数据准备 3.开窗函数之排序 需求:用三种排序方法查询学生的语文成绩排名,并降序显示 4.开窗函数分组 需求:按照科目来分类,使用三种排序方式来排序学生的成绩 5.聚合函数与分组配合使用 6.聚合函数同时和分组以及排序关键字配合使用 --需求1&…...

QTableWidget常用信号的功能

2023年11月18日,周六上午 itemPressed(QTableWidgetItem *item):当某个项目被按下时发出信号。itemClicked(QTableWidgetItem *item):当某个项目被单击时发出信号。itemDoubleClicked(QTableWidgetItem *item):当某个项目被双击时…...

Vue理解01

项目建立流程 项目文件夹终端vue ui可视化新建项目(需要一些时间)vscode打开项目npm run serve运行 架构理解: 首先打开的页面默认是index.htmlindex.html默认引用main.jsmain.js引用需要的页面,默认App.vue。Vue示例挂载可以在…...

4、FFmpeg命令行操作8

生成测试文件 找三个不同的视频每个视频截取10秒内容 ffmpeg -i 沙海02.mp4 -ss 00:05:00 -t 10 -codec copy 1.mp4 ffmpeg -i 复仇者联盟3.mp4 -ss 00:05:00 -t 10 -codec copy 2.mp4 ffmpeg -i 红海行动.mp4 -ss 00:05:00 -t 10 -codec copy 3.mp4 如果音视…...

【MySQL】索引与事务

作者主页:paper jie_博客 本文作者:大家好,我是paper jie,感谢你阅读本文,欢迎一建三连哦。 本文录入于《MySQL》专栏,本专栏是针对于大学生,编程小白精心打造的。笔者用重金(时间和精力)打造&a…...

切换为root用户后,conda:未找到命令

问题:切换为root用户后,conda:未找到命令 结论详细用户切换配置路径 结论 问题:切换为root用户后,conda:未找到命令 (anaconda) 解决:在~/.bashrc配置里增加conda的路径 详细 用户切换 1 切…...

Qt退出界面

void Dialog::on_pushButton_clicked() {if(ui->lineEdit->text() "admin" && ui->lineEdit_2->text() "123"){accept();//退出} }...

【数据标注】Label Studio用于机器学习标注

原文作者:我辈李想 版权声明:文章原创,转载时请务必加上原文超链接、作者信息和本声明。 文章目录 前言一、使用 Label Studio标注数据1.版本控制 二、Label Studio绑定机器学习后端三、重写机器学习后端四、通过api执行Label Studio动作 前言…...

py字符串转字符串数组

在Python中,你可以使用列表(list)来存储多个字符串。如果你有一个字符串,并且想要将其转换为字符串数组,你可以使用列表推导式(list comprehension)。这是一个简单的例子: # 原始字…...

强化学习各种符号含义解释

:状态 : 动作 : 奖励 : 奖励函数 : 非终结状态 : 全部状态,包括终结状态 : 动作集合 ℛ : 奖励集合 : 转移矩阵 : 离散时间步 : 回合内最终时间步 : 时间t的状态 : 时间t动作 : 时间t的奖励,通常为随机量,且由和决定 : 回报 : n步…...

Axure基础详解二十:中继器随机抽奖效果

效果演示 组件 一、中继器 建立一个“中继器”内部插入一个“正方形”,给“正方形”添加一个【样式效果】>>【选中状态】填充背景为红色,字体白色。在中继器表格中插入两列数据函数:【xuhao】(序号列,按12345……填写&…...

企业信息化与电子商务>供应链信息流

1.供应链信息流概念 供应链信息流是指整个供应链上信息的流动。它是一种虚拟形态,包括了供应链上的供需信息和管理信息,它伴随着物流的运作而不断产生。因此有效的供应链管理作为信息流的管理主要作用在于及时在供应链中传递需求和供给信息,…...

【Proteus仿真】【STM32单片机】防火防盗GSM智能家居设计

文章目录 一、功能简介二、软件设计三、实验现象联系作者 一、功能简介 本项目使用Proteus8仿真STM32单片机控制器,使用声光报警模块、LCD1602显示模块、DS18B20温度、烟雾传感器模块、按键模块、PCF8591 ADC模块、红外检测模块等。 主要功能: 系统运行…...

快速入门ESP32——开发环境配置PlatformIO IDE

相关文章 快速入门ESP32——开发环境配置Arduino IDE 快速入门ESP32——开发环境配置PlatformIO IDE 一、下载安装二、验证 一、下载安装 下载安装 vscode 安装PlatformIO插件 创建工程 二、验证 写一个简单的函数来验证一下功能 void setup() {// put your setup cod…...

Oxygen XML Editor 26版新功能

▲ 搜索“大龙谈智能内容”关注GongZongHao▲ 2023年10月26日,罗马尼亚SyncRO Soft公司发布Oxygen XML Editor、Oxygen Web Author和Oxygen Publish Engine 26版本。 1. Oxygen XML Editor 26新功能简介 AI助手 帮助写作者通过执行重复任务、审查语法、生成结构…...

Pikachu漏洞练习平台之SSRF(服务器端请求伪造)

注意区分CSRF和SSRF: CSRF:跨站请求伪造攻击,由客户端发起; SSRF:是服务器端请求伪造,由服务器发起。 SSRF形成的原因大都是由于服务端提供了从其他服务器应用获取数据的功能,但又没有对目标…...

WPF异步编程

在WPF应用程序中进行异步编程是非常重要的,因为这有助于保持用户界面的响应性,特别是当执行长时间运行的操作时,例如访问网络资源、进行大量的数据处理或调用耗时的I/O操作。 WPF的异步编程通常围绕以下几个关键概念: Dispatcher…...

同态加密定义,四大发展阶段总结,FHE系统正式定义-全同态加密

目录 同态加密定义 为什么采用电路模型? 四大发展阶段 总结 FHE系统正式定义...

Swift 协议扩展精进之路:解决 CoreData 托管实体子类的类型不匹配问题(下)

概述 在 Swift 开发语言中,各位秃头小码农们可以充分利用语法本身所带来的便利去劈荆斩棘。我们还可以恣意利用泛型、协议关联类型和协议扩展来进一步简化和优化我们复杂的代码需求。 不过,在涉及到多个子类派生于基类进行多态模拟的场景下,…...

华为OD机试-食堂供餐-二分法

import java.util.Arrays; import java.util.Scanner;public class DemoTest3 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseint a in.nextIn…...

基于Docker Compose部署Java微服务项目

一. 创建根项目 根项目&#xff08;父项目&#xff09;主要用于依赖管理 一些需要注意的点&#xff1a; 打包方式需要为 pom<modules>里需要注册子模块不要引入maven的打包插件&#xff0c;否则打包时会出问题 <?xml version"1.0" encoding"UTF-8…...

拉力测试cuda pytorch 把 4070显卡拉满

import torch import timedef stress_test_gpu(matrix_size16384, duration300):"""对GPU进行压力测试&#xff0c;通过持续的矩阵乘法来最大化GPU利用率参数:matrix_size: 矩阵维度大小&#xff0c;增大可提高计算复杂度duration: 测试持续时间&#xff08;秒&…...

前端开发面试题总结-JavaScript篇(一)

文章目录 JavaScript高频问答一、作用域与闭包1.什么是闭包&#xff08;Closure&#xff09;&#xff1f;闭包有什么应用场景和潜在问题&#xff1f;2.解释 JavaScript 的作用域链&#xff08;Scope Chain&#xff09; 二、原型与继承3.原型链是什么&#xff1f;如何实现继承&a…...

【Go语言基础【13】】函数、闭包、方法

文章目录 零、概述一、函数基础1、函数基础概念2、参数传递机制3、返回值特性3.1. 多返回值3.2. 命名返回值3.3. 错误处理 二、函数类型与高阶函数1. 函数类型定义2. 高阶函数&#xff08;函数作为参数、返回值&#xff09; 三、匿名函数与闭包1. 匿名函数&#xff08;Lambda函…...

纯 Java 项目(非 SpringBoot)集成 Mybatis-Plus 和 Mybatis-Plus-Join

纯 Java 项目&#xff08;非 SpringBoot&#xff09;集成 Mybatis-Plus 和 Mybatis-Plus-Join 1、依赖1.1、依赖版本1.2、pom.xml 2、代码2.1、SqlSession 构造器2.2、MybatisPlus代码生成器2.3、获取 config.yml 配置2.3.1、config.yml2.3.2、项目配置类 2.4、ftl 模板2.4.1、…...

scikit-learn机器学习

# 同时添加如下代码, 这样每次环境(kernel)启动的时候只要运行下方代码即可: # Also add the following code, # so that every time the environment (kernel) starts, # just run the following code: import sys sys.path.append(/home/aistudio/external-libraries)机…...

SQL Server 触发器调用存储过程实现发送 HTTP 请求

文章目录 需求分析解决第 1 步:前置条件,启用 OLE 自动化方式 1:使用 SQL 实现启用 OLE 自动化方式 2:Sql Server 2005启动OLE自动化方式 3:Sql Server 2008启动OLE自动化第 2 步:创建存储过程第 3 步:创建触发器扩展 - 如何调试?第 1 步:登录 SQL Server 2008第 2 步…...

渗透实战PortSwigger靶场:lab13存储型DOM XSS详解

进来是需要留言的&#xff0c;先用做简单的 html 标签测试 发现面的</h1>不见了 数据包中找到了一个loadCommentsWithVulnerableEscapeHtml.js 他是把用户输入的<>进行 html 编码&#xff0c;输入的<>当成字符串处理回显到页面中&#xff0c;看来只是把用户输…...