NestJS 初学最容易懵的不是语法而是一个请求进来之后代码到底怎么分层你可以先记住一句话Controller 接请求Service 做业务Module 把它们组装起来。下面用一套真实后端代码把这三层拆开看。1. 入口应用从哪里启动Nest 应用启动时会创建一个 App并把根模块挂上去import{NestFactory}fromnestjs/core;import{AppModule}from./app.module;asyncfunctionbootstrap(){constappawaitNestFactory.create(AppModule);app.enableCors();awaitapp.listen(3000);}bootstrap();真正业务代码不写在main.ts里。main.ts只负责创建应用挂全局配置CORS、异常处理等监听端口业务能力都在各个Module里。2. Module功能的「收纳盒」根模块通常长这样import{Module}fromnestjs/common;import{AuthModule}from./modules/auth/auth.module;import{DocumentsModule}from./modules/documents/documents.module;import{HealthController}from./health.controller;Module({imports:[AuthModule,DocumentsModule,// ... 其他业务模块],controllers:[HealthController],})exportclassAppModule{}读这段时抓住三点imports引入其他模块认证、文档……controllers本模块对外暴露的路由每个业务能力尽量一个 Module避免全塞进AppModule健康检查这种极简接口也可以直接挂在根模块import{Controller,Get}fromnestjs/common;Controller()exportclassHealthController{Get(health)health(){return{status:ok,timestamp:newDate().toISOString()};}}访问GET /health就会走到这里。这是理解 Controller 的最小例子。3. Controller只负责「接请求」再看一个更完整的认证 Controllerimport{Controller,Post,Get,Body,Headers,UseGuards}fromnestjs/common;import{AuthService}from./auth.service;import{JwtAuthGuard}from./jwt-auth.guard;Controller(api/auth)exportclassAuthController{constructor(privatereadonlyauthService:AuthService){}Post(login)login(Body()body:{email:string;password:string}){returnthis.authService.login(body.email,body.password);}Post(refresh)refresh(Body()body:{refreshToken:string}){returnthis.authService.refreshToken(body.refreshToken);}UseGuards(JwtAuthGuard)Get(me)me(Headers(authorization)auth:string){consttokenauth?.replace(Bearer ,);returnthis.authService.validateToken(token);}}这里有几个关键点写法含义Controller(api/auth)路由前缀Post(login)完整路径是POST /api/auth/loginBody()取请求体constructor(private readonly authService: AuthService)依赖注入Nest 帮你创建并传入 ServiceUseGuards(JwtAuthGuard)进这个接口前先做鉴权注意Controller几乎不写业务细节。密码对不对、怎么发 token全部丢给AuthService。CRUD 场景也一样比如文档接口Controller()exportclassDocumentsController{constructor(privatereadonlydocumentsService:DocumentsService){}Get(api/projects/:projectId/documents)findAll(Param(projectId)projectId:string){returnthis.documentsService.findAll(projectId);}Post(api/projects/:projectId/documents)create(Param(projectId)projectId:string,Body()data:{title:string;content:string}){returnthis.documentsService.create(projectId,data);}}模式始终是取参数 → 调 Service → 返回结果。4. Service业务真正发生的地方Service 用Injectable()标记表示可被注入import{Injectable,UnauthorizedException}fromnestjs/common;Injectable()exportclassAuthService{asynclogin(email:string,password:string){constuserthis.findUserByEmail(email);if(!user){thrownewUnauthorizedException(Invalid credentials);}constisPasswordValidawaitbcrypt.compare(password,user.password);if(!isPasswordValid){thrownewUnauthorizedException(Invalid credentials);}const{accessToken,refreshToken}awaitthis.generateTokens(user);awaitthis.createSession(user.id,refreshToken);const{password:_pwd,...userWithoutPassword}user;return{accessToken,refreshToken,user:userWithoutPassword,};}}登录流程都在 Service 里查用户校验密码签发 token / 建会话返回数据去掉密码字段Controller 只需要一行returnthis.authService.login(body.email,body.password);这也是 Nest 推荐的分层ControllerHTTP 细节路径、方法、参数Service业务规则校验、持久化、发 token5. 再回到 Module把零件装起来有了 Controller 和 Service还要告诉 Nest「它们属于同一个功能包」import{Module}fromnestjs/common;import{AuthController}from./auth.controller;import{AuthService}from./auth.service;import{JwtAuthGuard}from./jwt-auth.guard;Module({imports:[// JwtModule、PassportModule、PrismaModule 等依赖],controllers:[AuthController],providers:[AuthService,JwtAuthGuard],exports:[AuthService,JwtAuthGuard],})exportclassAuthModule{}对应关系可以这样记controllers谁对外提供 HTTP 接口providers谁提供可注入能力Service、Guard……exports哪些东西允许被其他模块继续用imports本模块依赖哪些外部能力文档模块更「典型」一点Module({imports:[PrismaModule],controllers:[DocumentsController],providers:[DocumentsService],exports:[DocumentsService],})exportclassDocumentsModule{}读到这里一张请求链路就清楚了HTTP 请求 → Controller解析路由/参数 → Service执行业务 → 数据库 / 缓存 / 外部服务 ← 返回业务结果 ← 返回 HTTP 响应Module 负责把这条链路上的类注册好Nest 的依赖注入再负责把它们「接上电」。6. 一张图串起来AppModule ├─ HealthController → GET /health ├─ AuthModule │ ├─ AuthController → POST /api/auth/login │ └─ AuthService → 校验账号、签发 token └─ DocumentsModule ├─ DocumentsController → GET/POST /api/projects/:id/documents └─ DocumentsService → 查库、创建、更新学 Nest 时建议每看到一个新功能都先问三句哪个Controller接这个请求哪个Service处理业务它们被哪个Module组装能答出来入门就过半了。7. 小结Nest 不是「把 Express 路由堆在一个文件里」而是按模块组织。Controller 薄、Service 厚这是最值得先养成的习惯。Module是装配车间声明依赖、暴露接口、控制边界。先读懂一个完整小模块比如 auth再扩到 CRUD比上来堆装饰器有效得多。系列导航下一篇NestJS 入门依赖注入到底解决了什么问题