# 一、Nest.js 简介
Nest.js 是一个用于构建高效、可靠和可扩展的服务器端应用程序的框架。它 完全使用 TypeScript 编写 ,但同时也 兼容纯 JavaScript 。Nest.js 结合了 OOP(面向对象编程) 、 FP(函数式编程) 和 FRP(函数响应式编程) 的特点。
其完全支持 TypeScript,并且结合了 面向切面(AOP) 的编程方式。
Nest.js 具有 Spring MVC 的风格,其中有 依赖注入 、 控制反转 等;而这些都是 借鉴了 Angualr 的成果。
先来看看在 Angular 当中,依赖注入(DI)和控制反转(IoC)是怎么体现的:
依赖注入
- 在 Angular 中,依赖注入是核心概念之一。它允许将依赖项(比如服务或对象)动态地提供给组件或服务,而不是在组件内部硬编码创建它们。
- 这种方法的好处是代码更加模块化,更易于测试和维护。
- Angular 通过其 DI 框架来实现这一点,主要是通过 “注入器”(injector)和 “提供者”(providers)来完成。注入器负责创建依赖项并将它们注入到组件或服务中。
控制反转
- 控制反转是一种设计原则,用于将组件的创建和管理控制权从组件自身转移到外部框架。
- 在 Angular 中,这主要通过依赖注入来实现。Angular 框架负责创建和管理服务或对象的实例,组件只需声明其依赖关系,框架则负责提供这些依赖项。
然后,我们可以了解一下 Nest.js 当中两者的体现方式:
依赖注入
- Nest.js 使用类似于 Angular 的依赖注入系统。在 Nest.js 中,你可以定义服务(service),然后在需要的地方(如控制器(controller))通过构造函数注入这些服务。
- 这种方法使得 Nest.js 应用中的组件之间的耦合度降低,提高了代码的可测试性和可维护性。
控制反转
- 与 Angular 类似,Nest.js 的控制反转是通过其依赖注入系统实现的。Nest.js 框架负责管理对象的生命周期和依赖关系,开发者只需关注业务逻辑。
Nest.js 的底层代码使用了 Express 和 Fastify,并在他们的基础上提供了一定程度的抽象,同时也将其 API 直接暴露给开发人员。这样可以轻松使用每个平台的无数第三方模块。
# 二、Nest.js 内置的两大框架:Express + Fastify
# Express
# 简介
我相信每一个使用过 Node.js 自己写过后端的同学都绝对知道这一款框架,经典中的经典。
Express 是一个 极简的 Node.js Web 应用框架,非常流行,被广泛用于构建各种 Web 应用和 API。它的主要特点包括:
- 简洁灵活:Express 提供了一种轻量级的方式来创建 Web 应用。它不强加太多额外的规范和结构,给开发者提供了很大的灵活性。
- 中间件架构:Express 使用中间件的概念来处理 HTTP 请求。中间件是一些函数,它们可以访问请求对象(req)、响应对象(res),以及 Web 应用中处于请求 - 响应循环流程中的中间件,一般用于完成特定的任务,例如解析请求体、日志记录、身份验证等。
- 路由系统:Express 有一个非常强大的路由系统,允许你以非常简洁的方式定义路由,并将不同的 HTTP 请求(GET、POST、PUT、DELETE 等)映射到对应的处理器函数。
- 社区支持:由于它的流行,Express 拥有一个庞大的社区,提供了大量的中间件和插件,可以轻松集成进 Express 应用中,极大地增强了其功能。
但究其根源,Express 本身是一个开箱即用,致力于 快速启动一个服务的框架 ,是比较难以去组织、维护一个相对大型、重量级的企业级项目的。因此目前市面上的很多大型 Node.js 框架,如 Koa.js、Egg.js 都是基于 Express 来封装。
# 使用示例(TS)
下面给一个简单的使用 Express+TS 来启动简单后台的示例。
首先新建一个存放 Express 项目的空目录,用 IDE 打开后在里面安装相关的依赖:
npm install express | |
npm install @types/express @types/node typescript ts-node --save-dev |
然后在根目录运行 tsc --init
来生成 tsconfig.json
来配置 TS 的编译器,并且可以按需调整其中的配置。
然后创建一个名为 server.ts
的文件,并写入以下代码:
import express from "express"; | |
const app = express(); | |
const port = 3000; | |
app.get("/", (req, res) => { | |
res.send({ hello: "world" }); | |
}); | |
app.listen(port, () => { | |
console.log(`Server running on http://localhost:${port}`); | |
}); |
设置完毕后,可以使用 TypeScript Node ( ts-node
) 来运行你的服务器:
ts-node server.ts |
上面的示例首先导入了 Express,然后创建了一个 Express 应用实例,并为根 URL ( '/'
) 定义了一个 GET 路由,该路由简单地发送一个 JSON 对象作为响应。最后监听在端口 3000 上。此时通过访问 http://localhost:3000
可以看到响应。
# Fastify
# 简介
Fastify 是一个更现代的、高性能的 Node.js 框架,以速度和低开销为其主要特点。Fastify 的主要特性包括:
- 高性能:Fastify 被设计为一个高性能的框架,能够处理大量的请求,同时保持较低的响应时间和资源消耗。
- 可扩展:Fastify 通过其提供的钩子(hook)、插件和装饰器(decorator)提供完整的可扩展性。
- 基于 Schema:即使这不是强制性的,我们仍建议使用 JSON Schema 来做路由(route)验证及输出内容的序列化,Fastify 在内部将 schema 编译为高效的函数并执行。
- 日志:日志是非常重要且代价高昂的。我们选择了最好的日志记录程序来尽量消除这一成本,这就是 Pino!
- 支持 TypeScript:开发组努力维护一个 TypeScript 类型声明文件,以便支持不断成长的 TypeScript 社区。
- 模式驱动:Fastify 使用 JSON Schema 来处理路由的输入和输出验证,这不仅提供了数据验证,还优化了序列化和解析操作,提高了性能。
- 丰富的插件生态系统:与 Express 类似,Fastify 也有一个健康的插件生态系统,可以通过插件来扩展其核心功能。
- 开发者友好:Fastify 提供了详细的文档和开发工具,使得开发和维护变得更加容易。
# 使用示例(TS)
和上面的 Express 启动应用类似,我们采用 Fastify 来编写一个差不多的后端服务示例。
首先新建一个存放 Fastify 项目的空目录,用 IDE 打开后在里面安装相关的依赖:
npm install fastify | |
npm install @types/node typescript ts-node --save-dev |
接下来,创建一个名为 server.ts
的文件,并写入以下代码:
import fastify from "fastify"; | |
const server = fastify(); | |
server.get("/", async (request, reply) => { | |
return { hello: "world" }; | |
}); | |
server.listen(3000, (err, address) => { | |
if (err) { | |
server.log.error(err); | |
process.exit(1); | |
} | |
console.log(`Server listening at ${address}`); | |
}); |
然后直接在控制台运行 ts-node server.ts
就可以启动了。最终的效果和上述 Express 启动的服务类似。