Skip to content

企业级 NestJS 项目完整指南

上一篇文章,我已经初步验证了 nest 框架的运行效果。但是我现在想要的是真正实战过程中的 nest 框架,它还需要做哪些配置?做哪些代码调整?能实现哪些功能?需要引入哪些插件或者第三方组件?它最终会成为具有什么样功能的项目?

本文档是 Nest 实战的第二篇,主要介绍 Nest 框架的配置、代码调整、功能实现、插件引入以及第三方组件的引入。也就是Nest 高级篇

Github 项目地址(DEMO)

An image

An image

An image

一、基础架构增强

1. 项目结构规范化

src/
├── common/           # 公共模块
│   ├── decorators/  # 自定义装饰器
│   ├── guards/      # 守卫
│   ├── filters/     # 异常过滤器
│   ├── interceptors/# 拦截器
│   └── middleware/  # 中间件
├── config/          # 配置文件
├── database/        # 数据库相关
├── modules/         # 业务模块
├── shared/          # 共享模块
└── utils/           # 工具函数

二、必须的配置和插件

1. 环境配置管理

bash
npm install @nestjs/config cross-env
typescript
// .env
NODE_ENV=development
PORT=3333
DATABASE_URL=mysql://user:password@localhost:3306/db
REDIS_URL=redis://localhost:6379
JWT_SECRET=bob-588
typescript
// main.ts
import { NestFactory } from "@nestjs/core";
import { ValidationPipe } from "@nestjs/common";
import { AppModule } from "./app.module";
import { ConfigService } from "./config/config.service";

async function bootstrap() {
  const app = await NestFactory.create(AppModule);

  // 全局验证管道
  app.useGlobalPipes(
    new ValidationPipe({
      whitelist: true,
      forbidNonWhitelisted: true,
      transform: true,
    })
  );

  // 获取配置服务
  const configService = app.get(ConfigService);

  // 验证必需的环境变量
  configService.validateRequired([
    "NODE_ENV",
    "PORT",
    "DATABASE_URL",
    "REDIS_URL",
    "JWT_SECRET",
  ]);

  // 启用CORS(开发环境)
  if (configService.app.isDevelopment) {
    app.enableCors({
      origin: true,
      credentials: true,
    });
  }

  const port = configService.app.port;
  await app.listen(port);

  console.log(`🚀 应用运行在 ${configService.app.nodeEnv} 模式`);
  console.log(`📡 服务地址: http://localhost:${port}`);
  console.log(
    `💾 数据库: ${configService.database.host}:${configService.database.port}`
  );
  console.log(
    `🔴 Redis: ${configService.redis.host}:${configService.redis.port}`
  );
}

bootstrap();

An image

2. 数据库集成(TypeORM)

bash
npm install @nestjs/typeorm typeorm mysql2
npm install pg pg-native # PostgreSQL
npm install mongodb # MongoDB
typescript
// database.module.ts
import { Module } from "@nestjs/common";
import { TypeOrmModule } from "@nestjs/typeorm";
import { ConfigService } from "../config/config.service";

@Module({
  imports: [
    TypeOrmModule.forRootAsync({
      inject: [ConfigService],
      useFactory: (configService: ConfigService) => ({
        ...configService.typeorm,
        // 连接重试配置
        retryAttempts: 10,
        retryDelay: 3000,
        // 连接池配置
        extra: {
          connectionLimit: 10,
          acquireTimeout: 60000,
          timeout: 60000,
        },
        // 时区配置
        timezone: "+08:00",
        // 字符集
        charset: "utf8mb4",
      }),
    }),
  ],
  exports: [TypeOrmModule],
})
export class DatabaseModule {}

3. 数据迁移和种子

bash
npm install typeorm-extension
typescript
// scripts/migration.ts
import { DataSource } from "typeorm";
import { User } from "../modules/users/user.entity";

export async function seedUsers(dataSource: DataSource) {
  const userRepository = dataSource.getRepository(User);

  const adminUser = userRepository.create({
    username: "admin",
    email: "admin@example.com",
    password: await hashPassword("admin123"),
    role: "admin",
  });

  await userRepository.save(adminUser);
}

三、安全配置

1. 身份验证(JWT)

bash
npm install @nestjs/passport passport passport-local
npm install @nestjs/jwt passport-jwt
npm install bcrypt
typescript
// auth.module.ts
import { JwtModule } from '@nestjs/jwt';
import { PassportModule } from '@nestjs/passport';

@Module({
  imports: [
    PassportModule.register({ defaultStrategy: 'jwt' }),
    JwtModule.registerAsync({
      imports: [ConfigModule],
      inject: [ConfigService],
      useFactory: (config: ConfigService) => ({
        secret: config.get('JWT_SECRET'),
        signOptions: {
          expiresIn: config.get('JWT_EXPIRES_IN', '7d'),
        },
      }),
    }),
  ],
  providers: [JwtStrategy, LocalStrategy],
})

2. 授权(RBAC)

typescript
// guards/roles.guard.ts
import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
import { Reflector } from '@nestjs/core';

@Injectable()
export class RolesGuard implements CanActivate {
  constructor(private reflector: Reflector) {}

  canActivate(context: ExecutionContext): boolean {
    const requiredRoles = this.reflector.get<string[]>(
      'roles',
      context.getHandler(),
    );

    if (!requiredRoles) return true;

    const request = context.switchToHttp().getRequest();
    const user = request.user;

    return requiredRoles.some((role) => user.roles?.includes(role));
  }
}

// 使用
@UseGuards(JwtAuthGuard, RolesGuard)
@Roles('admin', 'manager')
@Get('admin-only')
adminOnly() {
  return 'Admin access only';
}

3. 安全中间件

typescript
// main.ts
import helmet from "helmet";
import rateLimit from "express-rate-limit";
import * as csurf from "csurf";

async function bootstrap() {
  const app = await NestFactory.create(AppModule);

  // 安全头部
  app.use(helmet());

  // 速率限制
  app.use(
    rateLimit({
      windowMs: 15 * 60 * 1000, // 15分钟
      max: 100, // 每个IP限制100个请求
    })
  );

  // CORS配置
  app.enableCors({
    origin: ["http://localhost:3000", "https://your-domain.com"],
    credentials: true,
  });

  // 防止XSS攻击
  app.use((req, res, next) => {
    res.setHeader("X-Content-Type-Options", "nosniff");
    res.setHeader("X-Frame-Options", "DENY");
    res.setHeader("X-XSS-Protection", "1; mode=block");
    next();
  });
}

四、缓存和性能优化

1. Redis 缓存

bash
npm install cache-manager cache-manager-redis-store redis
typescript
// cache.module.ts
import { CacheModule } from '@nestjs/cache-manager';
import * as redisStore from 'cache-manager-redis-store';

@Module({
  imports: [
    CacheModule.registerAsync({
      imports: [ConfigModule],
      inject: [ConfigService],
      useFactory: (config: ConfigService) => ({
        store: redisStore,
        host: config.get('REDIS_HOST'),
        port: config.get('REDIS_PORT'),
        ttl: 600, // 10分钟
        max: 1000, // 最大缓存数量
      }),
    }),
  ],
})

2. 响应压缩

bash
npm install compression
typescript
// main.ts
import * as compression from "compression";

app.use(compression());

五、文件处理和上传

bash
npm install multer @types/multer
npm install sharp # 图片处理
typescript
// upload.service.ts
import { Injectable } from '@nestjs/common';
import { diskStorage } from 'multer';
import { extname } from 'path';

@Injectable()
export class UploadService {
  getMulterConfig() {
    return {
      storage: diskStorage({
        destination: './uploads',
        filename: (req, file, callback) => {
          const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1e9);
          const ext = extname(file.originalname);
          callback(null, `${file.fieldname}-${uniqueSuffix}${ext}`);
        },
      }),
      limits: {
        fileSize: 5 * 1024 * 1024, // 5MB
      },
      fileFilter: (req, file, callback) => {
        if (!file.originalname.match(/\.(jpg|jpeg|png|gif|pdf|doc|docx)$/)) {
          return callback(new Error('只允许上传图片和文档'), false);
        }
        callback(null, true);
      },
    };
  }
}

// 控制器中使用
@Post('upload')
@UseInterceptors(FileInterceptor('file'))
uploadFile(@UploadedFile() file: Express.Multer.File) {
  return {
    filename: file.filename,
    url: `/uploads/${file.filename}`,
    size: file.size,
  };
}

六、日志系统

bash
npm install winston winston-daily-rotate-file
npm install nest-winston
typescript
// logger.config.ts
import { utilities as nestWinstonModuleUtilities } from 'nest-winston';
import * as winston from 'winston';
import 'winston-daily-rotate-file';

export const winstonConfig = {
  transports: [
    new winston.transports.Console({
      format: winston.format.combine(
        winston.format.timestamp(),
        winston.format.ms(),
        nestWinstonModuleUtilities.format.nestLike('MyApp', {
          colors: true,
          prettyPrint: true,
        }),
      ),
    }),
    new winston.transports.DailyRotateFile({
      filename: 'logs/application-%DATE%.log',
      datePattern: 'YYYY-MM-DD',
      zippedArchive: true,
      maxSize: '20m',
      maxFiles: '14d',
      format: winston.format.combine(
        winston.format.timestamp(),
        winston.format.json(),
      ),
    }),
  ],
};

// 使用
import { WinstonModule } from 'nest-winston';

@Module({
  imports: [
    WinstonModule.forRoot(winstonConfig),
  ],
})

七、任务调度和队列

bash
npm install @nestjs/schedule bull @nestjs/bull
npm install bull-board # Bull队列管理界面
typescript
// tasks.module.ts
import { BullModule } from '@nestjs/bull';
import { ScheduleModule } from '@nestjs/schedule';

@Module({
  imports: [
    ScheduleModule.forRoot(),
    BullModule.forRootAsync({
      imports: [ConfigModule],
      inject: [ConfigService],
      useFactory: (config: ConfigService) => ({
        redis: {
          host: config.get('REDIS_HOST'),
          port: config.get('REDIS_PORT'),
        },
      }),
    }),
    BullModule.registerQueue({
      name: 'email',
      limiter: {
        max: 100,
        duration: 1000,
      },
    }),
  ],
})

八、API 文档(Swagger)

bash
npm install @nestjs/swagger swagger-ui-express
typescript
// main.ts
import { SwaggerModule, DocumentBuilder } from "@nestjs/swagger";

async function bootstrap() {
  const config = new DocumentBuilder()
    .setTitle("API文档")
    .setDescription("企业级API接口文档")
    .setVersion("1.0")
    .addBearerAuth()
    .addTag("users", "用户管理")
    .addTag("auth", "认证授权")
    .build();

  const document = SwaggerModule.createDocument(app, config);
  SwaggerModule.setup("api/docs", app, document);
}

九、监控和健康检查

bash
npm install @nestjs/terminus @godaddy/terminus
npm install @nestjs/mongoose mongoose # 如果需要MongoDB监控
typescript
// health.module.ts
import { TerminusModule } from '@nestjs/terminus';
import { HttpModule } from '@nestjs/axios';

@Module({
  imports: [
    TerminusModule.forRoot({
      errorLogStyle: 'pretty',
      gracefulShutdownTimeoutMs: 1000,
    }),
    HttpModule,
  ],
  controllers: [HealthController],
})

十、测试配置

typescript
// test/setup.ts
import { Test, TestingModule } from "@nestjs/testing";
import { INestApplication } from "@nestjs/common";
import * as request from "supertest";
import { AppModule } from "../src/app.module";

describe("AppController (e2e)", () => {
  let app: INestApplication;

  beforeAll(async () => {
    const moduleFixture: TestingModule = await Test.createTestingModule({
      imports: [AppModule],
    }).compile();

    app = moduleFixture.createNestApplication();
    await app.init();
  });

  afterAll(async () => {
    await app.close();
  });

  it("/users (GET)", () => {
    return request(app.getHttpServer()).get("/users").expect(200);
  });
});

十一、Docker 部署配置

dockerfile
# Dockerfile
FROM node:18-alpine AS development
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM node:18-alpine AS production
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm ci --only=production
COPY --from=development /usr/src/app/dist ./dist
EXPOSE 3000
CMD ["node", "dist/main"]
yaml
# docker-compose.yml
version: "3.8"
services:
  app:
    build:
      context: .
      target: production
    ports:
      - "3000:3000"
    environment:
      NODE_ENV: production
      DATABASE_URL: mysql://user:pass@db:3306/app
    depends_on:
      - db
      - redis
  db:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: app
    volumes:
      - mysql_data:/var/lib/mysql
  redis:
    image: redis:7-alpine
    command: redis-server --appendonly yes
    volumes:
      - redis_data:/data

volumes:
  mysql_data:
  redis_data:

十二、最终项目功能清单

一个完整的企业级 NestJS 项目通常包含:

核心功能

  1. 用户系统(注册、登录、权限管理)
  2. JWT 认证 + Refresh Token
  3. RBAC 权限控制
  4. 文件上传(本地+云存储)
  5. 邮件服务(通知、验证码)
  6. 短信服务(阿里云/腾讯云)
  7. 支付集成(支付宝、微信支付)
  8. 第三方登录(微信、QQ、GitHub)

高级特性

  1. 微服务架构(gRPC/TCP)
  2. WebSocket 实时通信
  3. GraphQL API
  4. SSR 服务端渲染
  5. 国际化 i18n
  6. 多租户支持
  7. 数据导出(Excel、PDF)
  8. API 限流和防刷

DevOps 支持

  1. CI/CD 配置(GitHub Actions/Jenkins)
  2. 容器化部署(Docker + K8s)
  3. 性能监控(APM 工具)
  4. 错误追踪(Sentry)
  5. 日志聚合(ELK/Logstash)
  6. API 网关(Kong/Traefik)

十三、最佳实践建议

  1. 使用 DTO 进行数据验证和转换
  2. 实现 Repository 模式(避免 Service 直接操作数据库)
  3. 使用 DTO Mapper(如 class-transformer)
  4. 实现软删除(isDeleted 字段)
  5. 数据分页标准化
  6. 统一响应格式
  7. 全局异常处理
  8. 请求 ID 跟踪
  9. API 版本管理
  10. 配置中心化

十四、项目启动脚本

json
{
  "scripts": {
    "start": "nest start",
    "start:dev": "nest start --watch",
    "start:debug": "nest start --debug --watch",
    "start:prod": "node dist/main",
    "lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
    "format": "prettier --write \"src/**/*.ts\"",
    "test": "jest",
    "test:watch": "jest --watch",
    "test:cov": "jest --coverage",
    "test:e2e": "jest --config ./test/jest-e2e.json",
    "typeorm": "ts-node ./node_modules/typeorm/cli",
    "migration:generate": "npm run typeorm migration:generate",
    "migration:run": "npm run typeorm migration:run",
    "seed": "ts-node scripts/seed.ts",
    "build": "nest build",
    "docker:build": "docker build -t myapp .",
    "docker:up": "docker-compose up -d",
    "docker:down": "docker-compose down"
  }
}

总结

一个企业级 NestJS 项目应该是:

  1. 可扩展的:模块化设计,易于添加新功能
  2. 可维护的:清晰的代码结构,完善的文档
  3. 高性能的:缓存、数据库优化、负载均衡
  4. 安全的:完善的认证授权、输入验证、安全防护
  5. 可监控的:完整的日志、性能监控、健康检查
  6. 易部署的:容器化、CI/CD、环境配置