作为一名前端开发者,当第一次接触 NestJS 时,一种强烈的熟悉感扑面而来------这目录结构、这装饰器语法、这模块化设计,不就是 Angular 吗?
事实上,这种相似性绝非巧合。本文将从两个维度带你深入理解 NestJS:
-
架构渊源:为什么 NestJS 和 Angular 如此相似?
-
实战基础:掌握 NestJS 中的各种 HTTP 请求处理方式
一、NestJS 与 Angular 的渊源
1.1 创始人背景
NestJS 由 Kamil Myśliwiec 于 2017 年创建,他是一位 Google Developer Expert。在官方文档中,他毫不讳言:
"The architecture is heavily inspired by Angular."
(NestJS 的架构深受 Angular 启发)
Kamil 创建 NestJS 的初衷是解决 Node.js 后端缺乏统一架构的问题。当时前端已有 Angular、React、Vue 等成熟框架,但后端 Node.js 生态中虽然库很多(如 Express),却没有提供开箱即用的应用架构。
1.2 架构对比
|--------|-----------------------|---------------|
| 概念 | Angular(前端) | NestJS(后端) |
| 模块化 | @NgModule() | @Module() |
| 依赖注入 | @Injectable() | @Injectable() |
| 控制器/组件 | @Component() | @Controller() |
| 服务层 | *.service.ts | *.service.ts |
| cli工具 | ng generate | nest generate |
| DTO/接口 | TypeScript Interfaces | DTO Classes |
1.3 全栈开发的优势
这种相似性带来了真实的开发优势:
-
心智模型统一:前端用 Angular,后端用 NestJS,团队可以在两种环境间无缝切换
-
代码共享:通过 Nx monorepo 可以共享 TypeScript 接口、DTO、验证逻辑
-
学习成本低:熟悉 Angular 的开发者可以在几天内上手 NestJS
这也是为什么现代全栈开发中经常出现 "A2N 技术栈"(Angular + NestJS + Nx)的组合。
二、NestJS HTTP 请求方式详解
下面通过一个完整的 CatsController 示例,详细讲解 NestJS 中各种请求方式的区别。
2.1 完整代码示例
import { Controller, Get, Query, Post, Body, Put, Param, Delete } from '@nestjs/common';
import { CreateCatDto, UpdateCatDto, ListAllEntities } from './dto';
@Controller('cats')
export class CatsController {
@Post()
create(@Body() createCatDto: CreateCatDto) {
return 'This action adds a new cat';
}
@Get()
findAll(@Query() query: ListAllEntities) {
return `This action returns all cats (limit: ${query.limit} items)`;
}
@Get(':id')
findOne(@Param('id') id: string) {
return `This action returns a #${id} cat`;
}
@Put(':id')
update(@Param('id') id: string, @Body() updateCatDto: UpdateCatDto) {
return `This action updates a #${id} cat`;
}
@Delete(':id')
remove(@Param('id') id: string) {
return `This action removes a #${id} cat`;
}
}
2.2 HTTP 方法与 CRUD 对应关系
|----------------|---------|------|---------------|------------------|-----|
| 装饰器 | HTTP 方法 | 语义 | 对应操作 | 示例路由 | 幂等性 |
| @Post() | POST | 创建资源 | Create | POST /cats | 非冥等 |
| @Get() | GET | 获取列表 | Read (列表) | GET /cats | 冥等 |
| @Get(':id') | GET | 获取单个 | Read (单条) | GET /cats/123 | 冥等 |
| @Put(':id') | PUT | 全量更新 | Update | PUT /cats/123 | 冥等 |
| @Delete(':id') | DELETE | 删除资源 | Delete | DELETE /cats/123 | 冥等 |
2.3 各方法详细解析
① @Post() - 创建资源
@Post()
create(@Body() createCatDto: CreateCatDto) {
return 'This action adds a new cat';
}
-
特性:非幂等,多次调用会创建多个资源
-
传参方式 :通过
@Body()获取请求体中的 JSON 数据
② @Get() - 获取资源列表
@Get()
findAll(@Query() query: ListAllEntities) {
return `This action returns all cats (limit: ${query.limit} items)`;
}
-
特性:幂等且安全,不修改服务器状态
-
传参方式 :通过
@Query()获取 URL 查询参数(如?limit=10&page=1)
③ @Get(':id') - 获取单个资源
@Get(':id')
findOne(@Param('id') id: string) {
return `This action returns a #${id} cat`;
}
-
特性:根据 ID 获取详情
-
传参方式 :通过
@Param('id')获取 URL 路径参数 -
请求示例:
④ @Put(':id') - 全量更新
@Put(':id')
update(@Param('id') id: string, @Body() updateCatDto: UpdateCatDto) {
return `This action updates a #${id} cat`;
}
-
特性:幂等,多次相同请求结果一致
-
重要区别 :PUT 是全量更新,客户端必须提供资源的全部字段
-
对比 PATCH:PATCH 是部分更新,只需发送要修改的字段
PUT vs PATCH 示例:
// PUT 请求:{ age: 3 } → 资源变成只有 age 字段,其他被清空
// PATCH 请求:{ age: 3 } → 只更新 age,其他字段保持不变
⑤ @Delete(':id') - 删除资源
@Delete(':id')
remove(@Param('id') id: string) {
return `This action removes a #${id} cat`;
}
-
特性:幂等,删除一次和多次结果相同(资源不存在后再次删除仍是"不存在"状态)
-
请求示例:
curl -X DELETE http://localhost:3000/cats/123
2.4 参数装饰器对比
|--------------|--------------------|----------------------|----------------------|---|
| 装饰器 | 数据来源 | 用途 | 示例 | |
| @Body() | 请求体 (Request Body) | POST/PUT 的表单/JSON 数据 | { "name": "Tom" } | |
| @Query() | URL 查询参数 | 过滤、分页、搜索 | ?limit=10&page=1 | |
| @Param('id') | URL 路径参数 | 资源标识 | /cats/123 中的 123 | |
三、完整请求示例汇总
# 1. 创建(Create)
curl -X POST http://localhost:3000/cats \
-H "Content-Type: application/json" \
-d '{"name":"Tom","age":2,"breed":"Persian"}'
# 2. 列表查询(Read All)
curl "http://localhost:3000/cats?limit=10"
# 3. 单条查询(Read One)
curl http://localhost:3000/cats/123
# 4. 更新(Update)
curl -X PUT http://localhost:3000/cats/123 \
-H "Content-Type: application/json" \
-d '{"name":"Tom","age":3,"breed":"Persian"}'
# 5. 删除(Delete)
curl -X DELETE http://localhost:3000/cats/123
四、总结
NestJS 的设计哲学
-
统一架构:借鉴 Angular 的模块化、依赖注入等成熟设计
-
TypeScript 优先:提供完整的类型支持
-
RESTful 规范:通过装饰器实现语义化的 API 设计
-
全栈友好:让前端开发者(尤其是 Angular 用户)能快速上手后端开发