nestjs实战(一):从 0 到 1 掌握企业级 Node.js 框架(新手也能秒懂模块/控制器/服务)
Nest.js 是一个用于构建高效、可扩展的 Node.js 服务端应用的框架。它使用渐进式 JavaScript,构建在 TypeScript 之上,并且结合了 OOP(面向对象编程)、FP(函数式编程)和 FRP(函数式响应式编程)的元素。
还在被 Nest.js 的模块、控制器、提供者搞得晕头转向?想不通依赖注入如何工作,更不懂如何组织大型项目?
今天这篇教程,全程围绕 Nest.js 的核心架构展开,从基础原理到实战接口,手把手教你用 Nest.js 实现标准的 RESTful API,新手也能跟着敲出效果,彻底搞懂 Nest.js 在企业级开发中的核心作用。
1. 先搞懂:Nest.js + 架构设计 = 企业级 Node.js 应用的灵魂
Nest.js 是一个用于构建高效、可扩展的 Node.js 服务端应用的框架。它使用渐进式 JavaScript,构建在 TypeScript 之上,并且结合了 OOP(面向对象编程)、FP(函数式编程)和 FRP(函数式响应式编程)的元素。
核心优势
-
模块化架构:应用程序被组织成模块(Modules),每个模块封装相关的控制器、服务等,结构清晰,易于维护和扩展。
-
依赖注入容器:内置强大的依赖注入(DI)系统,自动管理类的实例化和生命周期,降低代码耦合度。
-
平台无关:可以基于 Express(默认)或 Fastify 运行,提供灵活的底层 HTTP 服务器适配。
-
丰富的生态系统:提供大量官方和社区模块,如 TypeORM、Mongoose、GraphQL、WebSockets 等,开箱即用。
-
支持多种传输层:不仅能创建 HTTP 服务,还能轻松构建 WebSocket 网关、微服务等。
2. Nest.js 核心概念与工作原理
Nest.js 的核心是控制器(Controllers)、提供者(Providers)和模块(Modules)。它们是构建任何 Nest.js 应用程序的基石。
-
控制器:负责处理传入的请求并返回响应给客户端。它们通过装饰器(如
@Controller、@Get、@Post)来定义路由和 HTTP 方法。 -
提供者:负责处理具体的业务逻辑,可以被注入到控制器或其他提供者中。服务(Services)、存储库(Repositories)、工厂(Factories)等都属于提供者。它们通过
@Injectable()装饰器标记。 -
模块:使用
@Module()装饰器来组织应用程序结构。每个模块是一个包含控制器、提供者等的容器,可以导入其他模块或导出自己的提供者供其他模块使用。
工作流程(以处理一个 HTTP 请求为例):
-
客户端发起一个 HTTP 请求到服务器(如
GET /users)。 -
控制器中匹配到对应路由的处理器(Handler)被触发。
-
控制器调用提供者(如 UsersService)中的方法来执行实际的业务逻辑(例如从数据库查询用户)。
-
提供者执行逻辑并返回结果给控制器。
-
控制器将结果包装成 HTTP 响应发送回客户端。
这个过程通过依赖注入无缝连接:Nest.js 运行时会自动将 UsersService 的实例注入到 UsersController 的构造函数中。
2.1 环境准备与项目创建
第一步:环境准备
确保你的开发环境中安装了 Node.js (版本 20 或更高)。你可以使用 node -v 检查版本。

第二步:安装 Nest CLI
Nest CLI 是一个强大的命令行工具,可以帮助你快速搭建项目、生成代码文件等。
bash
npm i -g @nestjs/cli
第三步:创建新项目
使用 nest new 命令创建一个新项目,将 my-nest-project 替换为你想要的项目名称。
bash
nest new my-nest-project
CLI 会询问你希望使用哪种包管理器(npm、yarn 或 pnpm),选择你习惯的即可,如下图。

第四步:启动项目
进入项目目录并启动开发服务器。
bash
cd my-nest-project
npm run start:dev
访问 http://localhost:3000/,如果看到 “Hello World!”,说明项目已成功运行,如下图。

项目结构概览
创建好的项目结构大致如下:
text
my-nest-project/ ├── src/ │ ├── main.ts # 应用程序入口文件 │ ├── app.module.ts # 根模块 │ ├── app.controller.ts # 根控制器 │ └── app.service.ts # 根服务 ├── test/ # 测试文件夹 ├── package.json ├── tsconfig.json └── ...
3. 代码详细解释
核心文件协作流程图
为了更直观地理解这些文件如何协同工作,请看下图:

流程简述:
-
main.ts启动应用,加载AppModule。 -
AppModule声明了控制器AppController和服务AppService。 -
当客户端访问根路径时,
AppController的getHello方法被调用。 -
控制器通过依赖注入调用
AppService的getHello方法获取数据。 -
服务返回字符串,控制器将其作为 HTTP 响应发送给客户端。
我们已经成功创建并运行了一个 Nest.js 项目。但你是否对 src 文件夹下自动生成的几个核心文件感到好奇?它们各自扮演什么角色?又是如何协作的?本节将带你逐一拆解,彻底搞懂 Nest.js 应用的骨架。
-
main.ts是启动入口,负责创建应用和监听端口。 -
app.module.ts是根模块,负责组织其他组件。 -
app.controller.ts处理具体路由,接收请求并调用服务。 -
app.service.ts封装业务逻辑,可被注入。 -
app.controller.spec.ts确保控制器按预期工作。
下面我们逐个深入解析。
1. main.ts —— 应用程序的启动入口
main.ts 是整个 Nest.js 应用的起点,它负责启动应用并监听端口。其典型代码如下:
typescript
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule); // ① 创建应用实例
await app.listen(process.env.PORT ?? 3000); // ② 监听端口
}
bootstrap(); // ③ 启动函数调用
代码详解:
-
①
NestFactory.create(AppModule):这是创建 Nest 应用实例的核心方法。它接收一个根模块(AppModule)作为参数,Nest 会根据这个模块的配置(导入的模块、控制器、提供者等)来组装整个应用。这里创建的应用默认基于 Express 引擎。 -
②
app.listen(3000):启动 HTTP 服务器,监听 3000 端口。你可以修改为任何可用端口,或者从环境变量中读取(如process.env.PORT)。 -
③
bootstrap():调用异步启动函数,让应用跑起来。
扩展知识: 你可以在 main.ts 中进行一些全局配置,例如:
-
使用全局前缀:
app.setGlobalPrefix('api')会使所有路由自动加上/api。 -
启用 CORS:
app.enableCors()。 -
添加全局验证管道:
app.useGlobalPipes(new ValidationPipe())。 -
配置静态文件服务等。
2. app.module.ts —— 根模块
模块是 Nest.js 组织代码的基本单位。app.module.ts 是应用的根模块,它将所有其他模块和组件汇聚在一起。其典型代码如下:
typescript
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
@Module({
imports: [], // ① 导入其他模块
controllers: [AppController], // ② 声明本模块中的控制器
providers: [AppService], // ③ 声明本模块中的提供者(服务)
})
export class AppModule {}
代码详解:
-
@Module()装饰器:用于定义模块,它接受一个描述模块元数据的对象。 -
①
imports数组:导入其他模块,以便在当前模块中使用它们导出的提供者。初始项目为空,随着功能增加,你会在这里导入UsersModule、DatabaseModule等。 -
②
controllers数组:声明该模块下所有的控制器。Nest 会实例化这些控制器并注册路由。 -
③
providers数组:声明该模块下所有的提供者(通常是服务)。Nest 会将这些提供者放入依赖注入容器,使得它们可以被控制器或其他提供者注入。
关键点: 根模块负责引导整个应用。如果你创建了功能模块(如 UsersModule),需要将其导入到 imports 数组中,这样应用才能识别该模块的组件。
3. app.controller.ts —— 根控制器
控制器负责处理特定路径的 HTTP 请求。app.controller.ts 是默认生成的根控制器,它定义了一个简单的 GET 路由。典型代码如下:
typescript
import { Controller, Get } from '@nestjs/common';
import { AppService } from './app.service';
@Controller() // ① 基础路由前缀(此处为空)
export class AppController {
constructor(private readonly appService: AppService) {} // ② 注入 AppService
@Get() // ③ 处理 GET 请求,路径为 '/'(因为控制器前缀为空)
getHello(): string {
return this.appService.getHello(); // ④ 调用服务中的方法
}
}
代码详解:
-
①
@Controller()装饰器:标记该类为控制器,可以传入一个字符串作为路由前缀,例如@Controller('users')会使该控制器内的所有路由都加上/users前缀。这里为空,表示基础路径为/。 -
② 构造函数注入:通过声明
private readonly appService: AppService,Nest 会自动从依赖注入容器中提供AppService的实例。这是依赖注入的典型用法。 -
③
@Get()装饰器:修饰getHello方法,表示该方法处理 HTTP GET 请求。因为没有指定具体路径,所以它处理的是控制器基础路径(即/)的 GET 请求。 -
④ 业务逻辑委托:控制器本身不应包含复杂业务逻辑,而是调用服务(
AppService)的方法,将结果返回。
运行效果: 当你访问 http://localhost:3000/ 时,该方法被调用,返回字符串 "Hello World!"。
4. app.service.ts —— 根服务
服务(提供者)负责处理具体的业务逻辑,可被注入到控制器或其他服务中。app.service.ts 的典型代码如下:
typescript
import { Injectable } from '@nestjs/common';
@Injectable() // ① 标记该类为可注入的提供者
export class AppService {
getHello(): string { // ② 业务方法
return 'Hello World!';
}
}
代码详解:
-
①
@Injectable()装饰器:告诉 Nest 这个类是一个提供者,可以被依赖注入系统管理。只有添加了该装饰器的类才能被注入到其他类中。 -
②
getHello()方法:简单的业务逻辑方法,返回一个字符串。在真实项目中,这里可能会调用数据库、调用其他 API 等。
注意: 服务通常不直接处理 HTTP 细节(如状态码、请求头),这些应该由控制器负责。服务专注于业务逻辑,使其更易于测试和复用。
5. app.controller.spec.ts —— 控制器的单元测试
Nest.js 鼓励编写测试,并自动生成了控制器的测试文件。app.controller.spec.ts 是一个使用 Jest 框架的单元测试示例:
typescript
import { Test, TestingModule } from '@nestjs/testing';
import { AppController } from './app.controller';
import { AppService } from './app.service';
describe('AppController', () => {
let appController: AppController;
beforeEach(async () => {
const app: TestingModule = await Test.createTestingModule({
controllers: [AppController],
providers: [AppService],
}).compile();
appController = app.get<AppController>(AppController);
});
describe('root', () => {
it('should return "Hello World!"', () => {
expect(appController.getHello()).toBe('Hello World!');
});
});
});
代码详解:
-
Test.createTestingModule():创建一个用于测试的模块,模拟了 Nest 的模块系统。我们传入与生产环境相同的控制器和提供者。 -
.compile():编译测试模块,实例化其中的组件。 -
app.get<AppController>(AppController):从测试模块中获取AppController的实例。 -
测试用例:调用
appController.getHello()并验证返回值是否为'Hello World!'。
重要性: 单元测试确保控制器在隔离环境下正确工作。你可以运行 npm run test 来执行测试。
小结
-
main.ts是启动入口,负责创建应用和监听端口。 -
app.module.ts是根模块,负责组织其他组件。 -
app.controller.ts处理具体路由,接收请求并调用服务。 -
app.service.ts封装业务逻辑,可被注入。 -
app.controller.spec.ts确保控制器按预期工作。
理解这五个核心文件,你就掌握了 Nest.js 最基本的 MVC 架构。随着项目增长,你会在 src 下创建更多模块(如 users),每个模块都会包含类似的 controller、service、module 和测试文件。这种高度结构化的设计,使得 Nest.js 项目在变得庞大后依然清晰、可维护。
4.错误处理 Failed to execute command: git git init Git repository has not been initialized。
安装完成后,提示Failed to execute command: git git init Git repository has not been initialized。这个错误,是因为git没有安装

解决方案,新建项目时增加--skip-git 参数,或者安装git
nest new 项目名称 --skip-git
更多推荐
所有评论(0)