从零开始学 NestJS(一):为什么要学习 Nest

在 Node.js 开发中,搭建 Web 应用可以从最简单的原生 HTTP 模块开始。但随着项目规模扩大,手写的路由和逻辑会变得难以维护。此时,像 Express 这样的框架通过简化请求处理和路由管理,带来了开发上的便利。然而,当项目复杂度进一步增加,特别是在面对企业级应用时,Express 的灵活性可能成为一种限制。这时,NestJS 作为一种现代化、模块化的框架,提供了更强的架构设计能力。本文将从最基础的 Node.js HTTP 开发逐步展开,带你一步步理解为什么 NestJS 是应对复杂项目的最佳选择。


从最基础开始:使用 Node.js 原生 HTTP 模块

如果我们回到最原始的方式,可以使用 Node.js 提供的 http 模块来构建一个简单的服务器。代码如下:

typeScript 复制代码
const http = require('http');

const server = http.createServer((req, res) => {
  res.statusCode = 200;
  res.setHeader('Content-Type', 'text/plain');
  res.end('Hello, World!\n');
});

server.listen(3000, () => {
  console.log('Server running at http://127.0.0.1:3000/');
});

这个代码创建了一个简单的 HTTP 服务器,能够响应任何请求,并返回一个 "Hello, World!" 字符串。虽然这种方式非常基础,适合学习和理解 HTTP 请求的工作原理,但在实际项目中使用这种方式会变得非常繁琐,尤其是当你需要处理多个路由或复杂的请求时。

比如,如果我们需要处理多个路由,代码会逐渐失去可读性和可维护性:

typeScript 复制代码
const server = http.createServer((req, res) => {
  if (req.url === '/hello') {
    res.end('Hello Route!');
  } else if (req.url === '/goodbye') {
    res.end('Goodbye Route!');
  } else {
    res.statusCode = 404;
    res.end('Not Found');
  }
});

问题

  • 每次新增一个路由时,我们都得手动检查请求路径。
  • 没有任何中间件机制来处理常见的需求(如认证、日志记录等)。

由于这些局限,开发者通常会选择使用更简化的解决方案来帮助管理路由和中间件,而这时 Express 等轻量级框架便登场了。


走向简化:使用 Express 改善代码结构

Express 通过封装 HTTP 请求的处理,提供了简洁的 API 来创建路由、使用中间件,极大地提高了开发效率。

以下是使用 Express 实现相同功能的代码:

typeScript 复制代码
const express = require('express');
const app = express();

app.get('/hello', (req, res) => {
  res.send('Hello Route!');
});

app.get('/goodbye', (req, res) => {
  res.send('Goodbye Route!');
});

app.listen(3000, () => {
  console.log('Express server running on http://127.0.0.1:3000/');
});

改进点

  • 路由定义更加简洁,避免了手动判断 URL 和状态码。
  • 中间件的引入使得处理复杂的业务逻辑更加方便,比如认证、日志记录等。

但随着项目规模的扩大,Express 的灵活性可能带来一些问题:

1. 代码组织变得复杂

当项目增长时,往往有数十甚至上百个路由和业务逻辑需要处理。如果所有逻辑都堆积在几个文件里,维护变得极其困难。即使将路由拆分成多个文件,随着业务复杂性提升,路由文件仍然可能会变得臃肿。

例如,一个简单的用户管理路由可能很快会变得难以维护:

typeScript 复制代码
const express = require('express');
const app = express();

// 用户管理路由
app.get('/users', (req, res) => {
  res.send('List of users');
});

app.post('/users', (req, res) => {
  res.send('Create a new user');
});

app.put('/users/:id', (req, res) => {
  res.send('Update user');
});

app.delete('/users/:id', (req, res) => {
  res.send('Delete user');
});

当添加更多功能时,这种简单的结构不再足够灵活。随着业务逻辑的复杂化,你可能不得不手动拆分和组织这些文件,这会导致代码变得杂乱无章。

2. 缺少强制的架构规范

Express 并没有强制要求开发者遵循某种架构设计,因此每个开发者可能会以自己认为合理的方式组织项目代码。虽然这种灵活性在小型项目中非常有用,但在大型团队协作时会变成一种负担:

  • 没有统一的代码结构,不同开发者的代码风格差异巨大。
  • 难以维护和扩展,特别是当代码量达到数千行时,修改一个功能可能会影响到其他部分。

这时,NestJS 的结构化设计带来了明显的优势。


从简到优:NestJS 为复杂应用构建更好的架构

NestJS 提供了一种模块化、可扩展的架构,帮助开发者更轻松地管理项目结构。相比于 Express 的灵活性,NestJS 强制采用了一种分层架构,使代码更加清晰、可维护。

  • 模块化设计:项目可以被划分为多个独立的模块,每个模块专注于特定功能。
  • 控制器与服务分离:业务逻辑被明确分离到服务层,控制器仅负责处理请求。
  • 依赖注入:NestJS 提供了依赖注入机制,使得模块之间的依赖关系更加清晰,代码更加松耦合。

NestJS 的出现解决了许多 Express 项目中常见的代码组织问题。它不仅提供了一个一致的架构,同时保留了 Express 的所有功能,使得开发大型项目变得更加容易。

NestJS 示例:更清晰的架构

使用 NestJS 来重构上面的用户管理示例,代码会变得更加模块化和结构化:

控制器(users.controller.ts

typescript 复制代码
import { Controller, Get, Post, Put, Delete, Param, Body } from '@nestjs/common';
import { UsersService } from './users.service';
import { CreateUserDto, UpdateUserDto } from './dto';

@Controller('users')
export class UsersController {
  constructor(private readonly usersService: UsersService) {}

  @Get()
  getUsers() {
    return this.usersService.getAllUsers();
  }

  @Post()
  createUser(@Body() createUserDto: CreateUserDto) {
    return this.usersService.createUser(createUserDto);
  }

  @Put(':id')
  updateUser(@Param('id') id: string, @Body() updateUserDto: UpdateUserDto) {
    return this.usersService.updateUser(id, updateUserDto);
  }

  @Delete(':id')
  deleteUser(@Param('id') id: string) {
    return this.usersService.deleteUser(id);
  }
}

服务(users.service.ts

typescript 复制代码
import { Injectable } from '@nestjs/common';
import { CreateUserDto, UpdateUserDto } from './dto';

@Injectable()
export class UsersService {
  private users = [];

  getAllUsers() {
    return 'List of users';
  }

  createUser(createUserDto: CreateUserDto) {
    return 'Create a new user';
  }

  updateUser(id: string, updateUserDto: UpdateUserDto) {
    return 'Update user';
  }

  deleteUser(id: string) {
    return 'Delete user';
  }
}

在 NestJS 中,控制器和业务逻辑被清晰地分离开来,每个模块都有自己的职责范围。这样一来,即使项目规模扩大,代码的可读性和可维护性都能得到保证。


结论

通过从 Node.js 的原生 http 模块到 Express,再到 NestJS 的演变,我们可以看到代码组织的改进如何帮助开发者更好地管理和扩展应用程序。NestJS 提供了结构化的解决方案,使开发者能够轻松应对大型应用的复杂性。

正是这些特性,使得 NestJS 成为了构建现代企业级应用的首选工具。接下来的章节将会进一步深入 NestJS 的核心概念和实战技巧,帮助你快速上手并掌握这一强大的框架。

相关推荐
每天都要喝奶茶23 分钟前
vue3uniapp实现自定义拱形底部导航栏,解决首次闪烁问题
前端·vue.js·uni-app
May_Xu_24 分钟前
vue3+less使用主题定制(多主题定制)可切换主题
前端·javascript·vue.js·vue·less·css3
qq_4275060824 分钟前
less解决function中return写法在浏览器被识别成Object导致样式失败的问题
前端·css·less
Elastic 中国社区官方博客30 分钟前
将你的 Kibana Dev Console 请求导出到 Python 和 JavaScript 代码
大数据·开发语言·前端·javascript·python·elasticsearch·ecmascript
北京_宏哥1 小时前
《最新出炉》系列入门篇-Python+Playwright自动化测试-41-录制视频
前端·python·测试
小霖家的混江龙1 小时前
Vite 打包 H5 如何注入版本号
前端·vite
叶不休2 小时前
DOM---鼠标事件类型(移入移出)
开发语言·前端·javascript·css·chrome·前端框架·html
爱编程的鱼2 小时前
web前后端交互方式有哪些?
前端·okhttp
言6662 小时前
vue点击菜单,出现2个相同tab,啥原因
前端·javascript·vue.js
Z_ One Dream2 小时前
css 在 hover 子元素时,不要让父元素触发 hover 效果
前端·javascript·css