NestJS
NestJS 是一个基于 TypeScript/Node.js 的企业级后端框架,采用模块化设计,融合了 OOP(面向对象编程)、FP(函数式编程)和微服务架构。它底层支持 Express/Fastify,提供依赖注入、装饰器路由、GraphQL 集成等特性,适合构建高效、可维护的服务器端应用,尤其契合全栈 TypeScript 开发。
本指南将详细介绍如何在 CloudBase HTTP 云函数上开发和部署 NestJS 应用程序。
前提条件
在开始之前,请确保您已具备以下条件:
- Node.js 环境:版本 16.13 或更高(推荐 18.15+)
- npm 或 yarn:包管理工具
- NestJS CLI:全局安装 NestJS 命令行工具
- CloudBase 账号:已注册腾讯云账号并创建云开发环境
环境准备
1. 安装 NestJS CLI
# 全局安装 NestJS CLI
npm install -g @nestjs/cli
# 验证安装
nest --version
2. 创建 NestJS 应用
如果您已有 NestJS 应用,可以跳过此步骤。
# 创建新的 NestJS 应用
nest new nest-cloudbase-app
# 进入项目目录
cd nest-cloudbase-app
选择包管理器(推荐使用 npm):
? Which package manager would you ❤️ to use? (Use arrow keys)
❯ npm
yarn
pnpm
应用开发
1. 项目结构
创建完成后,您将得到以下项目结构:
nest-cloudbase-app/
├── src/
│ ├── app.controller.ts # 应用控制器
│ ├── app.module.ts # 应用模块
│ ├── app.service.ts # 应用服务
│ └── main.ts # 应用入口文件
├── test/ # 测试文件
├── package.json
├── tsconfig.json
└── nest-cli.json
2. 修改应用入口文件
编辑 src/main.ts 文件,配置端口为 9000(CloudBase HTTP 云函数要求):
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
// 启用 CORS
app.enableCors({
origin: true,
credentials: true,
});
// CloudBase HTTP 云函数要求使用 9000 端口
const port = process.env.PORT || 9000;
await app.listen(port, '0.0.0.0');
console.log(`Application is running on: http://localhost:${port}`);
}
bootstrap();
3. 创建示例 API
创建用户模块
# 生成用户模块
nest generate module users
nest generate controller users
nest generate service users
编辑用户控制器
编辑 src/users/users.controller.ts:
import { Controller, Get, Post, Body, Param, Put, Delete } from '@nestjs/common';
import { UsersService } from './users.service';
export interface User {
id: number;
name: string;
email: string;
}
@Controller('users')
export class UsersController {
constructor(private readonly usersService: UsersService) {}
@Get()
findAll(): User[] {
return this.usersService.findAll();
}
@Get(':id')
findOne(@Param('id') id: string): User {
return this.usersService.findOne(+id);
}
@Post()
create(@Body() user: Omit<User, 'id'>): User {
return this.usersService.create(user);
}
@Put(':id')
update(@Param('id') id: string, @Body() user: Partial<User>): User {
return this.usersService.update(+id, user);
}
@Delete(':id')
remove(@Param('id') id: string): { message: string } {
this.usersService.remove(+id);
return { message: `User ${id} deleted successfully` };
}
}
编辑用户服务
编辑 src/users/users.service.ts:
import { Injectable, NotFoundException } from '@nestjs/common';
export interface User {
id: number;
name: string;
email: string;
}
@Injectable()
export class UsersService {
private users: User[] = [
{ id: 1, name: 'John Doe', email: 'john@example.com' },
{ id: 2, name: 'Jane Smith', email: 'jane@example.com' },
];
findAll(): User[] {
return this.users;
}
findOne(id: number): User {
const user = this.users.find(user => user.id === id);
if (!user) {
throw new NotFoundException(`User with ID ${id} not found`);
}
return user;
}
create(userData: Omit<User, 'id'>): User {
const newUser: User = {
id: Math.max(...this.users.map(u => u.id), 0) + 1,
...userData,
};
this.users.push(newUser);
return newUser;
}
update(id: number, userData: Partial<User>): User {
const userIndex = this.users.findIndex(user => user.id === id);
if (userIndex === -1) {
throw new NotFoundException(`User with ID ${id} not found`);
}
this.users[userIndex] = { ...this.users[userIndex], ...userData };
return this.users[userIndex];
}
remove(id: number): void {
const userIndex = this.users.findIndex(user => user.id === id);
if (userIndex === -1) {
throw new NotFoundException(`User with ID ${id} not found`);
}
this.users.splice(userIndex, 1);
}
}
4. 添加健康检查端点
编辑 src/app.controller.ts:
import { Controller, Get } from '@nestjs/common';
import { AppService } from './app.service';
@Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
@Get()
getHello(): string {
return this.appService.getHello();
}
@Get('health')
getHealth(): { status: string; timestamp: string } {
return {
status: 'ok',
timestamp: new Date().toISOString(),
};
}
}
本地测试
1. 启动开发服务器
# 开发模式启动
npm run start:dev
# 或者生产模式启动
npm run build
npm run start:prod
2. 测试 API 端点
使用 curl 或 Postman 测试应用:
# 健康检查
curl http://localhost:9000/health
# 获取所有用户
curl http://localhost:9000/users
# 获取单个用户
curl http://localhost:9000/users/1
# 创建新用户
curl -X POST http://localhost:9000/users \
-H "Content-Type: application/json" \
-d '{"name":"Alice Johnson","email":"alice@example.com"}'
# 更新用户
curl -X PUT http://localhost:9000/users/1 \
-H "Content-Type: application/json" \
-d '{"name":"John Updated","email":"john.updated@example.com"}'
# 删除用户
curl -X DELETE http://localhost:9000/users/1
部署配置
1. 创建 scf_bootstrap 文件
💡 注意:
- 在 windows 下创建
scf_bootstrap文件时,优先使用nano scf_bootstrap或者vim scf_bootstrap创建- 在 windows 下使用 vscode 创建
scf_bootstrap文件时,部署到 HTTP 云函数可能会报错:scf_bootstrap文件不存在- 这个错误是因为脚本文件包含了 Windows 格式的回车符(^M),导致 Linux 无法正确识别解释器路径。这是 WSL 中常见的问题
在项目根目录创建 scf_bootstrap 文件(无扩展名):
#!/bin/sh
# 设置端口为 9000(CloudBase HTTP 云函数要求)
export PORT=9000
# 启动 NestJS 应用
npm run start:prod
2. 设置文件权限
chmod +x scf_bootstrap
3. 优化 package.json
确保 package.json 包含正确的启动脚本:
{
"scripts": {
"build": "nest build",
"start": "node dist/main",
"start:dev": "nest start --watch",
"start:debug": "nest start --debug --watch",
"start:prod": "node dist/main"
}
}
4. 创建 .gitignore
# 依赖
node_modules/
# 构建输出
dist/
build/
# 日志
*.log
npm-debug.log*
# 环境变量
.env
.env.local
.env.*.local
# IDE
.vscode/
.idea/
# 操作系统
.DS_Store
Thumbs.db