文章目录
- 1、安装
- 创建项目脚手架
- 运行应用程序
- 快速生成 `CRUD` 模块
- 2、核心文件简要概述
- 3、控制器
- 4、模块
- 5、中间件
- 6、守卫(Guard)—— 鉴权 / 权限
- 7、拦截器(Interceptor)—— 响应包装 / 日志 / 缓存
- 8、最简使用示例
NestJS 基于 Express、socket.io 封装的 nodejs 后端开发框架
1、安装
- Node.js:版本 ≥20(推荐使用最新 LTS 版本)
- 包管理器:npm(Node.js 自带)、yarn 或 pnpm
创建项目脚手架
npmi -g @nestjs/cli nest new project-name运行应用程序
npmrun start:dev快速生成CRUD模块
nest g resource user生成一个基础的 CRUD 功能
nest g mo<name># 生成 modulenest g co<name># 生成 controllernest g s<name># 生成 servicenest g gu<name># 生成 guardnest g pi<name># 生成 pipenest build# 生产编译nest start:prod# 生产运行2、核心文件简要概述
| 文件 | 描述 |
|---|---|
app.controller.ts | 一个具有单个路由的基本控制器。 |
app.controller.spec.ts | 控制器的单元测试。 |
app.module.ts | 应用程序的根模块。 |
app.service.ts | 一个具有单个方法的基本服务。 |
main.ts | 应用程序的入口文件,它使用核心函数NestFactory来创建 Nest 应用程序实例。 |
3、控制器
路由
@Controller():将指定一个可选的路径前缀,这样,我们就不需要为文件中的每个路由重复该路径部分。路由参数
@Get(':id'):当需要接收动态数据作为请求的一部分时,可以在路由路径中添加路由参数标记来捕获 URL 中的动态值。@Param():用于修饰方法参数,使得路由参数可以在方法内部通过该装饰参数的属性进行访问。路由通配符
@Get('abcd/*'):路由路径'abcd/*'将匹配abcd/、abcd/123、abcd/abc等路径。在基于字符串的路径中,连字符(-)和点号(.)会按字面意义解析。请求对象
@Req():需要访问客户端的请求详细信息时,可以通过在处理程序签名中使用@Req()装饰器来指示 Nest 注入请求对象。资源
@Get()、@Post()、@Put()、@Delete()、@Patch()、@Options()以及@Head()。此外,@All()可定义处理所有这些方法的端点。状态码
@HttpCode(...):响应的默认状态码通常为200,但 POST 请求除外,其默认状态码为201响应头
@Header('Cache-Control', 'no-store')重定向
@Redirect():接收两个可选参数:url和statusCode。若省略statusCode,其默认值为302(Found)。
4、模块
@Module()装饰器采用单个对象,其属性描述模块:
| providers | 将由 Nest 注入器实例化并且至少可以在该模块中共享的提供程序 |
| controllers | 此模块中定义的必须实例化的控制器集 |
| imports | 导出此模块所需的提供程序的导入模块列表 |
| exports | 这个模块提供的 providers 的子集应该在导入这个模块的其他模块中可用。你可以使用提供器本身或仅使用其令牌(provide 值) |
每个模块自动成为共享模块。一旦创建,它就可以被任何模块重复使用。假设我们想在多个其他模块之间共享CatsService的实例。为此,我们首先需要通过将该提供者添加到模块的exports数组来导出CatsService,如下所示:
import{Module}from'@nestjs/common';import{CatsController}from'./cats.controller';import{CatsService}from'./cats.service';@Module({controllers:[CatsController],providers:[CatsService],exports:[CatsService]})exportclassCatsModule{}5、中间件
- 本质:在请求到达控制器之前,对
req/res进行拦截、加工、终止或放行。 - 接口:必须实现
NestMiddleware的use(req, res, next)方法。 - 注册位置:只能在模块类的
configure(consumer: MiddlewareConsumer)方法里绑定,可精细控制路由与HTTP 方法。
示例:
import{Module,NestModule,RequestMethod,MiddlewareConsumer}from'@nestjs/common';import{LoggerMiddleware}from'./common/middleware/logger.middleware';import{CatsModule}from'./cats/cats.module';@Module({imports:[CatsModule],})exportclassAppModuleimplementsNestModule{configure(consumer:MiddlewareConsumer){consumer.apply(LoggerMiddleware).forRoutes({path:'cats',method:RequestMethod.GET});}}警告
使用
express适配器时,NestJS 应用默认会注册body-parser包中的json和urlencoded中间件。这意味着如果你想通过MiddlewareConsumer自定义该中间件,就需要在使用NestFactory.create()创建应用时将bodyParser标志设为false来禁用全局中间件。
6、守卫(Guard)—— 鉴权 / 权限
必须实现CanActivate接口。
示例:简易 JWT 守卫(伪代码)
@Injectable()exportclassJwtAuthGuardimplementsCanActivate{canActivate(context:ExecutionContext):boolean{constrequest=context.switchToHttp().getRequest();returnrequest.headers.authorization==='Bearer valid-token';}}使用:
- 方法/
@UseGuards(JwtAuthGuard) - 全局:
app.useGlobalGuards(new JwtAuthGuard())
7、拦截器(Interceptor)—— 响应包装 / 日志 / 缓存
实现NestInterceptor接口。
示例:统一包装响应格式
@Injectable()exportclassTransformInterceptor<T>implementsNestInterceptor<T,{data:T}>{intercept(context:ExecutionContext,next:CallHandler){returnnext.handle().pipe(map(data=>({data})));}}全局注册:
app.useGlobalInterceptors(newTransformInterceptor())此后所有正常响应都会变成
{"data":...原始内容}8、最简使用示例
1. 生成 cats 模块
nest g resource cats# 交互选择 REST + 不生成 CRUD → 回车即可目录结构(自动生成):
src └── cats ├── cats.controller.ts ├── cats.module.ts └── cats.service.ts2. 代码编写
cats.service.ts
import{Injectable}from'@nestjs/common';@Injectable()exportclassCatsService{privatereadonlycats=['tom','garfield','mimi'];findAll():string[]{returnthis.cats;}}cats.controller.ts
import{Controller,Get}from'@nestjs/common';import{CatsService}from'./cats.service';@Controller('cats')exportclassCatsController{constructor(privatereadonlycatsService:CatsService){}@Get()findAll(){return{data:this.catsService.findAll()};}}浏览器 / Postman 访问
http://localhost:3000/cats
返回:
{"data":["tom","garfield","mimi"]}3. 单元测试
cats.controller.spec.ts(放在src/cats/下)
import{Test,TestingModule}from'@nestjs/testing';import{CatsController}from'./cats.controller';import{CatsService}from'./cats.service';describe('CatsController',()=>{letcontroller:CatsController;letservice:CatsService;beforeEach(async()=>{constmodule:TestingModule=awaitTest.createTestingModule({controllers:[CatsController],providers:[CatsService],}).compile();controller=module.get<CatsController>(CatsController);service=module.get<CatsService>(CatsService);});it('should return cat array',()=>{jest.spyOn(service,'findAll').mockReturnValue(['mock-cat']);expect(controller.findAll()).toEqual({data:['mock-cat']});});});跑测试:
npmtestcats.controller.spec.ts