Nest.js全栈开发终极实践:TypeORM+微服务+Docker构建高可用企业级应用
文章目录
- **第一部分:认识Nest.js与基础环境搭建**
- **1.1 什么是Nest.js?**
- **1.2 环境准备**
- **1.3 创建第一个项目**
- **1.4 启动开发服务器**
- **1.5 核心文件解读**
- **第二部分:基础控制器与路由**
- **2.1 控制器的作用**
- **2.2 创建自定义控制器**
- **2.3 路由参数处理**
- **2.4 状态码处理**
- **2.5 完整示例**
- **2.6 测试你的API**
- **关键概念总结**
- **第三部分:服务层与依赖注入**
- **3.1 为什么需要服务层?**
- **3.2 创建第一个服务**
- **3.3 依赖注入实战**
- **3.4 模块(Module)的作用**
- **3.5 完整流程测试**
- **3.6 依赖注入原理图解**
- **核心概念对比**
- **第四部分:数据库集成(TypeORM + PostgreSQL)**
- **4.1 准备工作**
- **4.2 配置数据库连接**
- **4.3 创建第一个实体(Entity)**
- **4.4 修改服务层操作数据库**
- **4.5 修改用户模块**
- **4.6 数据验证(DTO)**
- **4.7 完整API测试**
- **4.8 错误处理示例**
- **数据库操作关键API**
- **第五部分:身份认证(JWT策略)**
- **5.1 认证方案概述**
- **5.2 安装必要依赖**
- **5.3 用户实体增强**
- **5.4 配置JWT模块**
- **5.5 实现认证服务**
- **5.6 创建策略守卫**
- **5.7 实现认证控制器**
- **5.8 保护路由**
- **5.9 测试认证流程**
- **5.10 安全增强建议**
- **认证核心组件**
- **第六部分:异常处理与日志**
- **6.1 异常处理的重要性**
- **6.2 创建自定义异常过滤器**
- **6.3 全局注册过滤器**
- **6.4 使用内置HTTP异常**
- **6.5 日志记录配置**
- **6.6 集成Winston日志**
- **6.7 请求日志中间件**
- **6.8 错误追踪集成(Sentry示例)**
- **6.9 测试验证**
- **6.10 最佳实践建议**
- **异常处理核心机制**
- **第七部分:单元测试与E2E测试**
- **7.1 测试金字塔模型**
- **7.2 初始化测试环境**
- **7.3 服务层单元测试**
- **7.4 控制器层测试**
- **7.5 端到端测试(E2E)**
- **7.6 运行与解读测试**
- **7.7 测试最佳实践**
- **测试类型对比**
- **第八部分:部署与生产环境优化**
- **8.1 Docker容器化部署**
- **8.2 环境变量配置**
- **8.3 性能优化策略**
- **8.4 健康检查与监控**
- **8.5 日志收集方案**
- **8.6 部署验证**
- **8.7 生产环境检查清单**
- **部署架构示意图**
- **第九部分:微服务架构进阶**
- **9.1 微服务核心概念**
- **9.2 创建基础微服务**
- **9.3 实现gRPC通信**
- **9.4 RabbitMQ消息队列集成**
- **9.5 分布式事务处理(Saga模式示例)**
- **9.6 微服务通信模式对比**
- **9.7 服务发现与负载均衡**
- **9.8 测试微服务通信**
- **9.9 生产环境注意事项**
- **微服务架构核心组件**
- **第十部分:前端集成与全栈实践**
- **10.1 Swagger API文档集成**
- **10.2 前端项目配置(以React为例)**
- **10.3 实现登录认证流程**
- **10.4 前端路由保护(React示例)**
- **10.5 全栈调试技巧**
- **10.6 部署联调配置**
- **全栈开发关键点总结**
- **项目完整工作流**
第一部分:认识Nest.js与基础环境搭建
1.1 什么是Nest.js?
- Node.js后端框架(类似Express/Koa但更结构化)
- 使用TypeScript构建(也支持JavaScript)
- 结合了面向对象编程(OOP)+ 函数式编程(FP)
- 内置依赖注入、模块化架构
- 适合构建高效、可靠且易维护的服务端应用
1.2 环境准备
步骤1:安装Node.js
- 前往官网下载LTS版本(建议v18+)
- 安装完成后验证:
node -v # 显示版本号 npm -v # 显示版本号
步骤2:安装Nest CLI
npm install -g @nestjs/cli
1.3 创建第一个项目
nest new my-first-project
选择包管理器(推荐使用npm或yarn)
目录结构说明:
my-first-project/
├── src/
│ ├── app.controller.ts # 控制器(处理HTTP请求)
│ ├── app.service.ts # 服务(业务逻辑)
│ ├── app.module.ts # 根模块(组织应用结构)
│ └── main.ts # 应用入口文件
1.4 启动开发服务器
cd my-first-project
npm run start:dev
访问 http://localhost:3000 看到"Hello World!"
1.5 核心文件解读
main.ts(应用入口):
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';async function bootstrap() {const app = await NestFactory.create(AppModule); // 创建应用实例await app.listen(3000); // 监听端口
}
bootstrap();
app.controller.ts(示例控制器):
import { Controller, Get } from '@nestjs/common';
import { AppService } from './app.service';@Controller() // 控制器装饰器
export class AppController {constructor(private readonly appService: AppService) {} // 依赖注入@Get() // 处理GET请求getHello(): string {return this.appService.getHello();}
}
第二部分:基础控制器与路由
2.1 控制器的作用
- 负责处理客户端请求
- 通过装饰器定义路由路径
- 调用服务层处理业务逻辑
- 返回HTTP响应
2.2 创建自定义控制器
步骤1:生成新控制器
nest generate controller user
# 或简写 nest g co user
生成文件 src/user/user.controller.ts
步骤2:基础路由示例
// user.controller.ts
import { Controller, Get } from '@nestjs/common';@Controller('users') // 定义路由前缀 /users
export class UserController {@Get() // 处理 /users 的GET请求findAll(): string {return 'All users';}@Get('profile') // 处理 /users/profile 的GET请求getProfile(): string {return 'User profile';}
}
2.3 路由参数处理
示例1:路径参数
@Get(':id') // 匹配 /users/123 形式的请求
findOne(@Param('id') id: string): string {return `User ID: ${id}`;
}
示例2:查询参数
@Get('search')
search(@Query('name') name: string): string {return `Searching for: ${name}`;
}
示例3:POST请求体
@Post()
create(@Body() userData: any): string {return `Created user: ${JSON.stringify(userData)}`;
}
2.4 状态码处理
- 默认GET返回200,POST返回201
- 手动指定状态码:
@Post()
@HttpCode(202) // 自定义状态码
createWithStatus() {return 'Created with custom status';
}
2.5 完整示例
import { Controller, Get, Post, Param, Query, Body, HttpCode } from '@nestjs/common';@Controller('users')
export class UserController {@Get()findAll(): string {return 'User list';}@Post()create(@Body() user: { name: string }): string {return `Created user: ${user.name}`;}@Get(':id')findOne(@Param('id') id: string): string {return `User ID: ${id}`;}@Get('search')search(@Query('keyword') keyword: string): string {return `Search keyword: ${keyword}`;}
}
2.6 测试你的API
-
使用Postman或curl测试:
# GET请求示例 curl http://localhost:3000/users curl http://localhost:3000/users/123 curl http://localhost:3000/users/search?keyword=john# POST请求示例 curl -X POST -H "Content-Type: application/json" -d '{"name":"Alice"}' http://localhost:3000/users -
观察返回结果是否符合预期
关键概念总结
| 装饰器 | 作用 | 示例 |
|---|---|---|
@Controller | 定义控制器类并设置路由前缀 | @Controller('users') |
@Get | 处理GET请求 | @Get(':id') |
@Post | 处理POST请求 | @Post() |
@Param | 获取路径参数 | @Param('id') |
@Query | 获取查询参数 | @Query('page') |
@Body | 获取请求体数据 | @Body() userData |
@HttpCode | 设置响应状态码 | @HttpCode(204) |
第三部分:服务层与依赖注入
3.1 为什么需要服务层?
- 遵循单一职责原则(控制器只处理请求/响应)
- 集中存放业务逻辑
- 方便代码复用和测试
- 通过依赖注入实现解耦
3.2 创建第一个服务
步骤1:生成服务文件
nest generate service user
# 或简写 nest g s user
生成文件:
src/user/user.service.ts(服务类)src/user/user.service.spec.ts(测试文件)
步骤2:基础服务示例
// user.service.ts
import { Injectable } from '@nestjs/common';@Injectable() // 标记为可注入的类
export class UserService {private users = [{ id: 1, name: 'John' },{ id: 2, name: 'Alice' }];getAllUsers() {return this.users;}createUser(name: string) {const newUser = { id: Date.now(), name };this.users.push(newUser);return newUser;}
}
3.3 依赖注入实战
改造控制器(user.controller.ts):
import { Controller, Get, Post, Body } from '@nestjs/common';
import { UserService } from './user.service';@Controller('users')
export class UserController {constructor(private readonly userService: UserService) {} // 依赖注入@Get()getAllUsers() {return this.userService.getAllUsers();}@Post()createUser(@Body('name') name: string) {return this.userService.createUser(name);}
}
3.4 模块(Module)的作用
查看自动生成的 user.module.ts:
import { Module } from '@nestjs/common';
import { UserService } from './user.service';
import { UserController } from './user.controller';@Module({controllers: [UserController],providers: [UserService], // 注册服务
})
export class UserModule {}
关键点:
- 模块是Nest的组织单元
providers数组注册可注入的类- 通过
@Global()可以创建全局模块
3.5 完整流程测试
-
通过Postman发送请求:
GET http://localhost:3000/users POST http://localhost:3000/users Body: { "name": "Bob" } -
观察响应结果:
// GET 响应 [{ "id": 1, "name": "John" },{ "id": 2, "name": "Alice" } ]// POST 响应 { "id": 1625641654845, "name": "Bob" }
3.6 依赖注入原理图解
+---------------+
| Controller |
|---------------| +---------------+
| constructor( |<--------| UserService |
| userService) | +---------------+
+---------------+▲| 通过@Module装饰器的providers数组注册
+---------------+
| Module |
|---------------|
| providers: [ |
| UserService |
| ] |
+---------------+
核心概念对比
| 组件 | 职责 | 关键装饰器 |
|---|---|---|
| 控制器(Controller) | 处理HTTP请求/响应 | @Controller |
| 服务(Service) | 实现业务逻辑 | @Injectable |
| 模块(Module) | 组织应用结构,管理依赖关系 | @Module |
接下来计划讲解:
第四部分:数据库集成(TypeORM + PostgreSQL)
包括:
- TypeORM基本配置
- 实体(Entity)创建
- CRUD操作实现
- 数据验证与DTO
第四部分:数据库集成(TypeORM + PostgreSQL)
4.1 准备工作
-
安装所需依赖:
npm install @nestjs/typeorm typeorm pg@nestjs/typeorm: Nest的TypeORM集成包typeorm: ORM框架pg: PostgreSQL驱动
-
确保已安装PostgreSQL数据库(本地或使用云服务)
4.2 配置数据库连接
修改app.module.ts:
import { TypeOrmModule } from '@nestjs/typeorm';@Module({imports: [TypeOrmModule.forRoot({type: 'postgres',host: 'localhost', // 数据库地址port: 5432, // 数据库端口username: 'postgres', // 数据库用户名password: 'your_password', // 数据库密码database: 'nestdemo', // 数据库名称entities: [__dirname + '/**/*.entity{.ts,.js}'], // 自动扫描实体文件synchronize: true, // 开发环境自动同步数据库结构(生产环境禁用!)}),UserModule,],
})
export class AppModule {}
4.3 创建第一个实体(Entity)
新建src/user/user.entity.ts:
import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';@Entity() // 标记为数据库实体
export class User {@PrimaryGeneratedColumn() // 自增主键id: number;@Column({ length: 50 }) // 字符串列,长度限制50name: string;@Column({ unique: true }) // 唯一约束email: string;@Column({ default: () => 'CURRENT_TIMESTAMP' }) // 默认值createdAt: Date;
}
4.4 修改服务层操作数据库
更新user.service.ts:
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { User } from './user.entity';@Injectable()
export class UserService {constructor(@InjectRepository(User) // 注入用户实体仓库private userRepository: Repository<User>,) {}async findAll(): Promise<User[]> {return this.userRepository.find();}async create(userData: Partial<User>): Promise<User> {const newUser = this.userRepository.create(userData);return this.userRepository.save(newUser);}async findOne(id: number): Promise<User | null> {return this.userRepository.findOne({ where: { id } });}async remove(id: number): Promise<void> {await this.userRepository.delete(id);}
}
4.5 修改用户模块
更新user.module.ts:
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { User } from './user.entity';
import { UserService } from './user.service';
import { UserController } from './user.controller';@Module({imports: [TypeOrmModule.forFeature([User])], // 注册实体到模块controllers: [UserController],providers: [UserService],
})
export class UserModule {}
4.6 数据验证(DTO)
-
安装验证库:
npm install class-validator class-transformer -
创建
src/user/dto/create-user.dto.ts:import { IsString, IsEmail, Length } from 'class-validator';export class CreateUserDto {@IsString()@Length(2, 50)name: string;@IsEmail()email: string; } -
更新控制器:
import { Body, ValidationPipe } from '@nestjs/common';@Post() async create(@Body(new ValidationPipe()) createUserDto: CreateUserDto, // 自动验证 ) {return this.userService.create(createUserDto); }
4.7 完整API测试
# 创建用户
curl -X POST -H "Content-Type: application/json" \
-d '{"name":"Lisa","email":"lisa@example.com"}' \
http://localhost:3000/users# 获取所有用户
curl http://localhost:3000/users# 获取单个用户
curl http://localhost:3000/users/1# 删除用户
curl -X DELETE http://localhost:3000/users/1
4.8 错误处理示例
// 在控制器中处理查找异常
@Get(':id')
async findOne(@Param('id') id: string) {const user = await this.userService.findOne(+id);if (!user) {throw new NotFoundException('User not found'); // 自动返回404}return user;
}
数据库操作关键API
| 方法 | 作用 | 示例 |
|---|---|---|
repository.find() | 获取所有记录 | userRepository.find() |
repository.findOne() | 获取单条记录 | findOne({ where: { id } }) |
repository.save() | 创建/更新记录 | save(user) |
repository.delete() | 删除记录 | delete(id) |
接下来计划讲解:
第五部分:身份认证(JWT策略)
包括:
- 用户注册/登录实现
- Passport.js集成
- JWT签发与验证
- 路由守卫使用
第五部分:身份认证(JWT策略)
5.1 认证方案概述
5.2 安装必要依赖
npm install @nestjs/passport passport passport-jwt @nestjs/jwt bcrypt
npm install @types/passport-jwt @types/bcrypt --save-dev
5.3 用户实体增强
// user.entity.ts
import { BeforeInsert } from 'typeorm';@Entity()
export class User {// ...其他字段@Column()password: string;@BeforeInsert() // 自动加密密码async hashPassword() {this.password = await bcrypt.hash(this.password, 10);}
}
5.4 配置JWT模块
// auth.module.ts
import { JwtModule } from '@nestjs/jwt';@Module({imports: [JwtModule.register({global: true,secret: 'your-secret-key', // 生产环境应使用环境变量signOptions: { expiresIn: '1h' },}),],// ...
})
export class AuthModule {}
5.5 实现认证服务
// auth.service.ts
import { compare } from 'bcrypt';@Injectable()
export class AuthService {constructor(@InjectRepository(User)private usersRepository: Repository<User>,private jwtService: JwtService,) {}async validateUser(email: string, pass: string): Promise<any> {const user = await this.usersRepository.findOne({ where: { email } });if (user && await compare(pass, user.password)) {const { password, ...result } = user; // 移除密码字段return result;}return null;}async login(user: User) {const payload = { email: user.email, sub: user.id };return {access_token: this.jwtService.sign(payload),};}
}
5.6 创建策略守卫
// jwt.strategy.ts
import { ExtractJwt, Strategy } from 'passport-jwt';@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {constructor() {super({jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),ignoreExpiration: false,secretOrKey: 'your-secret-key',});}async validate(payload: any) {return { userId: payload.sub, email: payload.email };}
}
5.7 实现认证控制器
// auth.controller.ts
@Controller('auth')
export class AuthController {constructor(private authService: AuthService) {}@Post('login')async login(@Body() loginDto: LoginDto) {const user = await this.authService.validateUser(loginDto.email,loginDto.password,);if (!user) {throw new UnauthorizedException('Invalid credentials');}return this.authService.login(user);}@Post('register')async register(@Body() createUserDto: CreateUserDto) {return this.authService.register(createUserDto);}
}
5.8 保护路由
// user.controller.ts
@Get('profile')
@UseGuards(AuthGuard('jwt')) // 添加守卫
async getProfile(@Request() req) {return req.user;
}
5.9 测试认证流程
# 注册用户
curl -X POST -H "Content-Type: application/json" \
-d '{"name":"test","email":"test@example.com","password":"123456"}' \
http://localhost:3000/auth/register# 登录获取Token
curl -X POST -H "Content-Type: application/json" \
-d '{"email":"test@example.com","password":"123456"}' \
http://localhost:3000/auth/login# 访问受保护资源
curl -H "Authorization: Bearer your-token" \
http://localhost:3000/users/profile
5.10 安全增强建议
- 使用环境变量存储密钥
- 实现密码强度验证
- 添加刷新令牌机制
- 设置合理的令牌有效期
- 记录认证日志
认证核心组件
| 组件 | 作用 | 关键方法/装饰器 |
|---|---|---|
JwtModule | JWT配置模块 | register() |
JwtStrategy | 验证请求携带的JWT | validate() |
AuthGuard | 路由守卫 | @UseGuards(AuthGuard()) |
bcrypt | 密码哈希处理 | hash(), compare() |
@nestjs/jwt | JWT签发与验证 | sign(), verify() |
第六部分:异常处理与日志
6.1 异常处理的重要性
6.2 创建自定义异常过滤器
步骤1:生成过滤器
nest generate filter common/exceptions/http-exception
步骤2:实现过滤器逻辑
// http-exception.filter.ts
import {ExceptionFilter,Catch,ArgumentsHost,HttpException,
} from '@nestjs/common';
import { Request, Response } from 'express';@Catch(HttpException)
export class HttpExceptionFilter implements ExceptionFilter {catch(exception: HttpException, host: ArgumentsHost) {const ctx = host.switchToHttp();const response = ctx.getResponse<Response>();const request = ctx.getRequest<Request>();const status = exception.getStatus();response.status(status).json({statusCode: status,timestamp: new Date().toISOString(),path: request.url,message: exception.message || 'Unknown error',});}
}
6.3 全局注册过滤器
// main.ts
async function bootstrap() {const app = await NestFactory.create(AppModule);app.useGlobalFilters(new HttpExceptionFilter()); // 注册全局过滤器await app.listen(3000);
}
6.4 使用内置HTTP异常
// user.controller.ts
@Get(':id')
async findOne(@Param('id') id: string) {const user = await this.userService.findOne(+id);if (!user) {throw new NotFoundException(`User ${id} not found`);}return user;
}
6.5 日志记录配置
启用默认日志
// main.ts
const app = await NestFactory.create(AppModule, {logger: ['log', 'error', 'warn', 'debug', 'verbose'],
});
自定义日志服务
// logger.service.ts
import { LoggerService } from '@nestjs/common';export class MyLogger implements LoggerService {log(message: string) {console.log(`[LOG] ${new Date().toISOString()} - ${message}`);}error(message: string, trace: string) {console.error(`[ERROR] ${new Date().toISOString()} - ${message}`, trace);}warn(message: string) {console.warn(`[WARN] ${new Date().toISOString()} - ${message}`);}
}// main.ts
const app = await NestFactory.create(AppModule, {logger: new MyLogger(),
});
6.6 集成Winston日志
- 安装依赖:
npm install winston @types/winston
- 创建日志配置文件:
// logger/logger.config.ts
import { createLogger, format, transports } from 'winston';export const winstonConfig = {level: 'info',format: format.combine(format.timestamp(),format.printf(({ timestamp, level, message }) => {return `${timestamp} [${level}]: ${message}`;})),transports: [new transports.Console(),new transports.File({ filename: 'logs/error.log', level: 'error' }),new transports.File({ filename: 'logs/combined.log' }),],
};
- 创建NestJS适配器:
// logger/winston.logger.ts
import { LoggerService } from '@nestjs/common';
import { createLogger, Logger } from 'winston';
import { winstonConfig } from './logger.config';export class WinstonLogger implements LoggerService {private logger: Logger;constructor() {this.logger = createLogger(winstonConfig);}log(message: string) {this.logger.info(message);}error(message: string, trace: string) {this.logger.error(`${message} - ${trace}`);}warn(message: string) {this.logger.warn(message);}debug(message: string) {this.logger.debug(message);}verbose(message: string) {this.logger.verbose(message);}
}
6.7 请求日志中间件
// logger/request.logger.middleware.ts
import { Injectable, NestMiddleware } from '@nestjs/common';
import { Request, Response, NextFunction } from 'express';@Injectable()
export class RequestLoggerMiddleware implements NestMiddleware {use(req: Request, res: Response, next: NextFunction) {const start = Date.now();const { method, originalUrl } = req;res.on('finish', () => {const duration = Date.now() - start;const { statusCode } = res;console.log(`[${method}] ${originalUrl} - ${statusCode} (${duration}ms)`,);});next();}
}// app.module.ts
export class AppModule implements NestModule {configure(consumer: MiddlewareConsumer) {consumer.apply(RequestLoggerMiddleware).forRoutes('*');}
}
6.8 错误追踪集成(Sentry示例)
- 安装依赖:
npm install @sentry/node @sentry/tracing
- 配置Sentry:
// sentry.config.ts
import * as Sentry from '@sentry/node';Sentry.init({dsn: 'your-dsn-here',tracesSampleRate: 1.0,
});
- 集成到异常过滤器:
// http-exception.filter.ts
catch(exception: HttpException, host: ArgumentsHost) {const ctx = host.switchToHttp();const request = ctx.getRequest<Request>();Sentry.captureException(exception, {extra: {path: request.url,method: request.method,body: request.body,},});// ...原有处理逻辑
}
6.9 测试验证
# 触发404错误
curl http://localhost:3000/nonexistent# 查看日志文件
tail -f logs/error.log# 预期输出示例
2023-08-20T10:00:00.000Z [ERROR] 404 - Cannot GET /nonexistent
6.10 最佳实践建议
-
使用不同日志级别:
verbose: 详细调试信息debug: 调试信息log: 常规日志warn: 警告信息error: 错误信息
-
日志文件管理:
- 使用logrotate进行日志轮换
- 敏感信息过滤
- 按日期分割日志文件
-
生产环境注意事项:
- 禁用
synchronize选项 - 设置适当的日志级别
- 使用集中式日志系统(ELK/Splunk)
- 禁用
异常处理核心机制
| 组件 | 作用 | 关键方法/装饰器 |
|---|---|---|
ExceptionFilter | 捕获并处理异常 | @Catch() |
HttpException | 预定义的HTTP异常 | new BadRequestException() |
LoggerService | 日志接口 | log(), error() |
Middleware | 记录请求信息 | implements NestMiddleware |
第七部分:单元测试与E2E测试
7.1 测试金字塔模型
7.2 初始化测试环境
项目已内置测试配置:
test/目录:存放测试相关配置jest.config.js:Jest测试框架配置package.json脚本:{"scripts": {"test": "jest","test:watch": "jest --watch","test:cov": "jest --coverage"} }
7.3 服务层单元测试
测试目标:UserService
创建测试文件:user.service.spec.ts
import { Test, TestingModule } from '@nestjs/testing';
import { getRepositoryToken } from '@nestjs/typeorm';
import { User } from './user.entity';
import { UserService } from './user.service';// 模拟Repository
const mockRepository = {find: jest.fn(),findOne: jest.fn(),save: jest.fn(),delete: jest.fn(),
};describe('UserService', () => {let service: UserService;beforeEach(async () => {const module: TestingModule = await Test.createTestingModule({providers: [UserService,{provide: getRepositoryToken(User),useValue: mockRepository,},],}).compile();service = module.get<UserService>(UserService);});afterEach(() => {jest.clearAllMocks();});describe('findAll', () => {it('应返回用户数组', async () => {const mockUsers = [{ id: 1, name: 'Test' }];mockRepository.find.mockResolvedValue(mockUsers);const result = await service.findAll();expect(result).toEqual(mockUsers);expect(mockRepository.find).toHaveBeenCalledTimes(1);});});describe('create', () => {it('应成功创建用户', async () => {const newUser = { name: 'New' };mockRepository.save.mockResolvedValue({ id: 1, ...newUser });const result = await service.create(newUser);expect(result).toHaveProperty('id', 1);expect(mockRepository.save).toHaveBeenCalledWith(newUser);});});
});
7.4 控制器层测试
测试目标:UserController
创建测试文件:user.controller.spec.ts
import { Test, TestingModule } from '@nestjs/testing';
import { UserController } from './user.controller';
import { UserService } from './user.service';describe('UserController', () => {let controller: UserController;const mockUserService = {findAll: jest.fn().mockResolvedValue([{ id: 1 }]),create: jest.fn().mockImplementation((dto) => Promise.resolve({ id: 1, ...dto })),};beforeEach(async () => {const module: TestingModule = await Test.createTestingModule({controllers: [UserController],providers: [{provide: UserService,useValue: mockUserService,},],}).compile();controller = module.get<UserController>(UserController);});it('GET /users 应返回用户列表', async () => {await expect(controller.getAllUsers()).resolves.toEqual([{ id: 1 }]);expect(mockUserService.findAll).toHaveBeenCalled();});it('POST /users 应创建新用户', async () => {const dto = { name: 'Test' };await expect(controller.createUser(dto)).resolves.toEqual({id: 1,...dto,});expect(mockUserService.create).toHaveBeenCalledWith(dto);});
});
7.5 端到端测试(E2E)
创建测试文件:app.e2e-spec.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('/ (GET)', () => {return request(app.getHttpServer()).get('/').expect(200).expect('Hello World!');});describe('用户模块', () => {it('GET /users 应返回空数组', () => {return request(app.getHttpServer()).get('/users').expect(200).expect([]);});it('POST /users 应创建用户', async () => {const response = await request(app.getHttpServer()).post('/users').send({ name: 'E2E Test' }).expect(201);expect(response.body).toHaveProperty('id');expect(response.body.name).toBe('E2E Test');});});
});
7.6 运行与解读测试
执行测试命令:
# 运行全部测试
npm run test# 开发时监听模式
npm run test:watch# 生成覆盖率报告
npm run test:cov
覆盖率报告示例:
----------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
----------------|---------|----------|---------|---------|-------------------
All files | 92 | 85 | 90 | 92 | user.service | 100 | 100 | 100 | 100 | user.controller| 95 | 80 | 90 | 95 | 32
----------------|---------|----------|---------|---------|-------------------
7.7 测试最佳实践
-
测试命名规范:
describe('场景描述', () => {it('应完成特定行为', () => {// 测试逻辑}); }); -
测试三部曲:
- 准备(Arrange):设置测试数据和模拟
- 执行(Act):调用被测试方法
- 断言(Assert):验证结果
-
测试隔离原则:
- 每个测试用例独立运行
- 使用
beforeEach/afterEach重置状态 - 避免测试间的依赖关系
-
测试数据库策略:
// 使用测试专用数据库 TypeOrmModule.forRoot({database: 'test_db',synchronize: true, })
测试类型对比
| 测试类型 | 测试范围 | 执行速度 | 维护成本 | 适合场景 |
|---|---|---|---|---|
| 单元测试 | 单个类/方法 | 快 | 低 | 核心业务逻辑验证 |
| 集成测试 | 模块间交互 | 中 | 中 | 服务层与数据库交互 |
| E2E测试 | 完整系统流程 | 慢 | 高 | 用户操作流程验证 |
第八部分:部署与生产环境优化
8.1 Docker容器化部署
步骤1:创建Dockerfile
# 使用Node.js官方镜像
FROM node:18-alpine# 设置工作目录
WORKDIR /app# 复制依赖文件
COPY package*.json ./# 安装依赖(生产环境不装devDependencies)
RUN npm install --only=production# 复制项目文件
COPY . .# 构建项目(如果需要编译TypeScript)
RUN npm run build# 暴露端口
EXPOSE 3000# 启动命令
CMD ["npm", "run", "start:prod"]
步骤2:创建docker-compose.yml
version: '3.8'services:app:build: .ports:- "3000:3000"environment:- NODE_ENV=productiondepends_on:- dbdb:image: postgres:15environment:POSTGRES_USER: postgresPOSTGRES_PASSWORD: yoursecurepasswordPOSTGRES_DB: nestprodvolumes:- pgdata:/var/lib/postgresql/dataports:- "5432:5432"volumes:pgdata:
步骤3:构建并启动容器
docker-compose up -d --build
8.2 环境变量配置
步骤1:安装配置模块
npm install @nestjs/config
步骤2:创建.env文件
# .env.production
DATABASE_HOST=db
DATABASE_PORT=5432
DATABASE_USER=postgres
DATABASE_PASSWORD=yoursecurepassword
DATABASE_NAME=nestprod
JWT_SECRET=prod_secret_key
步骤3:更新app.module.ts
import { ConfigModule } from '@nestjs/config';@Module({imports: [ConfigModule.forRoot({envFilePath: `.env.${process.env.NODE_ENV}`,isGlobal: true,}),TypeOrmModule.forRootAsync({imports: [ConfigModule],useFactory: (config: ConfigService) => ({type: 'postgres',host: config.get('DATABASE_HOST'),port: config.get('DATABASE_PORT'),username: config.get('DATABASE_USER'),password: config.get('DATABASE_PASSWORD'),database: config.get('DATABASE_NAME'),entities: [__dirname + '/**/*.entity{.ts,.js}'],synchronize: false, // 生产环境必须关闭!}),inject: [ConfigService],}),],
})
8.3 性能优化策略
1. 启用压缩
// main.ts
import compression from 'compression';async function bootstrap() {const app = await NestFactory.create(AppModule);app.use(compression()); // 添加GZIP压缩
}
2. 集群模式(利用多核CPU)
// main.ts
import { clusterize } from '@nestjs/clusterize';async function bootstrap() {await clusterize({workers: process.env.NODE_ENV === 'production' ? 'max' : 1,bootstrap: async () => {const app = await NestFactory.create(AppModule);await app.listen(3000);},});
}
3. 缓存策略
// 安装缓存模块
npm install cache-manager @nestjs/cache-manager// app.module.ts
import { CacheModule } from '@nestjs/cache-manager';@Module({imports: [CacheModule.register({ttl: 60, // 缓存时间(秒)max: 1000, // 最大缓存数isGlobal: true,}),],
})
8.4 健康检查与监控
1. 添加终止信号处理
// main.ts
async function bootstrap() {const app = await NestFactory.create(AppModule);// 优雅关闭process.on('SIGTERM', () => {app.close().then(() => {console.log('Application closed');process.exit(0);});});
}
2. 集成健康检查
npm install @nestjs/terminus
// health.controller.ts
import { Controller, Get } from '@nestjs/common';
import { HealthCheckService, HealthCheck } from '@nestjs/terminus';@Controller('health')
export class HealthController {constructor(private health: HealthCheckService) {}@Get()@HealthCheck()check() {return this.health.check([]);}
}
3. Prometheus监控(可选)
npm install @nestjs/metrics prom-client
// metrics.module.ts
import { Module } from '@nestjs/common';
import { PrometheusModule } from '@nestjs/metrics';@Module({imports: [PrometheusModule.register()],
})
export class MetricsModule {}
8.5 日志收集方案
1. 生产环境日志配置
// winston.config.prod.ts
export const winstonConfig = {transports: [new transports.File({ filename: 'logs/error.log', level: 'error',maxsize: 1024 * 1024 * 10, // 10MBmaxFiles: 7 }),new transports.File({filename: 'logs/combined.log',maxsize: 1024 * 1024 * 50, // 50MBmaxFiles: 14})]
};
2. 日志查询命令
# 查看实时日志
tail -f logs/combined.log# 根据时间过滤日志
grep '2023-08-20T10' logs/error.log
8.6 部署验证
# 检查容器状态
docker ps -a# 查看应用日志
docker logs <container_id># 测试健康检查端点
curl http://localhost:3000/health# 压力测试(安装wrk)
wrk -t12 -c400 -d30s http://localhost:3000/users
8.7 生产环境检查清单
- 禁用
synchronize: true - 使用HTTPS加密通信
- 配置防火墙规则
- 设置自动备份策略
- 实施速率限制
- 定期安全扫描
- 监控CPU/内存使用
- 设置报警阈值
部署架构示意图
第九部分:微服务架构进阶
9.1 微服务核心概念
9.2 创建基础微服务
步骤1:安装依赖
npm install @nestjs/microservices
步骤2:创建用户服务(TCP通信)
// user-service/src/main.ts
import { NestFactory } from '@nestjs/core';
import { MicroserviceOptions, Transport } from '@nestjs/microservices';
import { UserModule } from './user.module';async function bootstrap() {const app = await NestFactory.createMicroservice<MicroserviceOptions>(UserModule,{transport: Transport.TCP,options: {host: 'localhost',port: 3001,},},);await app.listen();
}
bootstrap();
步骤3:定义用户服务接口
// shared/user.interface.ts
export interface User {id: number;name: string;
}export interface FindUserRequest {id: number;
}export interface CreateUserRequest {name: string;
}
9.3 实现gRPC通信
步骤1:定义proto文件
// proto/user.proto
syntax = "proto3";package user;service UserService {rpc FindUser (FindUserRequest) returns (User) {}rpc CreateUser (CreateUserRequest) returns (User) {}
}message FindUserRequest {int32 id = 1;
}message CreateUserRequest {string name = 1;
}message User {int32 id = 1;string name = 2;
}
步骤2:配置gRPC服务端
// user-service/src/main.ts
{transport: Transport.GRPC,options: {package: 'user',protoPath: join(__dirname, 'proto/user.proto'),url: 'localhost:50051',},
}
步骤3:实现gRPC客户端
// api-gateway/src/user.client.ts
@Client({transport: Transport.GRPC,options: {package: 'user',protoPath: join(__dirname, 'proto/user.proto'),url: 'localhost:50051',},
})
client: ClientGrpc;private userService: UserService;onModuleInit() {this.userService = this.client.getService<UserService>('UserService');
}@Get('users/:id')
async findUser(@Param('id') id: number) {return this.userService.findUser({ id });
}
9.4 RabbitMQ消息队列集成
步骤1:安装依赖
npm install @nestjs/microservices amqplib amqp-connection-manager
步骤2:配置消息生产者
// order-service/src/order.service.ts
@Injectable()
export class OrderService {constructor(@Inject('RABBITMQ_CLIENT') private readonly client: ClientProxy,) {}async createOrder(orderData: CreateOrderDto) {// 发送创建订单事件this.client.emit('order_created', orderData);return { status: 'processing' };}
}
步骤3:配置消息消费者
// payment-service/src/payment.consumer.ts
@Controller()
export class PaymentController {@EventPattern('order_created')async handleOrderCreated(data: CreateOrderDto) {// 处理支付逻辑console.log('Processing payment for order:', data);// 发送支付完成事件this.client.emit('payment_processed', {orderId: data.id,status: 'paid',});}
}
9.5 分布式事务处理(Saga模式示例)
// 订单创建Saga流程
async createOrderSaga(orderData) {try {// 1. 创建订单(Pending状态)const order = await this.orderService.createPendingOrder(orderData);// 2. 扣减库存await this.inventoryService.reserveStock(order.items);// 3. 处理支付const payment = await this.paymentService.processPayment(order);// 4. 确认订单await this.orderService.confirmOrder(order.id);return order;} catch (error) {// 补偿操作await this.orderService.cancelOrder(order.id);await this.inventoryService.releaseStock(order.items);throw error;}
}
9.6 微服务通信模式对比
| 模式 | 协议 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|---|
| 请求-响应 | HTTP/REST | 简单查询操作 | 简单易用 | 同步阻塞 |
| gRPC | HTTP/2 | 高性能内部通信 | 高效、强类型 | 需要proto定义 |
| 消息队列 | AMQP | 异步任务处理 | 解耦、可靠 | 架构复杂度增加 |
| 事件驱动 | Pub/Sub | 实时数据更新 | 实时性高 | 消息顺序需处理 |
9.7 服务发现与负载均衡
使用Consul示例配置:
// 服务注册
import { ConsulService } from '@nestjs/consul';@Module({providers: [{provide: 'CONSUL_CLIENT',useFactory: () => {return new ConsulService({host: 'consul-server',port: '8500',});},},],
})
客户端负载均衡:
@Client({transport: Transport.TCP,options: {serviceName: 'user-service',loadBalancer: new RoundRobinLoadBalancer(),discoverer: new ConsulDiscoverer({host: 'consul-server',port: 8500,}),},
})
9.8 测试微服务通信
// 测试gRPC服务
describe('UserService (gRPC)', () => {let client: UserServiceClient;beforeAll(async () => {const packageDefinition = await loadPackageDefinition(loadSync(join(__dirname, 'proto/user.proto')));const proto = packageDefinition.user as any;client = new proto.UserService('localhost:50051',credentials.createInsecure());});it('should return user details', (done) => {client.findUser({ id: 1 }, (err, response) => {expect(response).toEqual({ id: 1, name: 'Test User' });done();});});
});
9.9 生产环境注意事项
-
服务监控:
- 使用Prometheus + Grafana监控服务指标
- 实现健康检查端点
-
容错处理:
// 断路器模式 @Get('users/:id') @UseFilters(CircuitBreakerFilter) async getUser(@Param('id') id: string) {return this.userService.findUser(id); } -
日志追踪:
- 集成OpenTelemetry实现分布式追踪
- 使用唯一请求ID串联日志
-
安全策略:
- 服务间TLS加密通信
- JWT认证传递
- 速率限制
微服务架构核心组件
| 组件 | 作用 | 常用工具 |
|---|---|---|
| API网关 | 请求路由、聚合、认证 | Kong, NestJS网关 |
| 服务注册中心 | 服务发现与管理 | Consul, etcd, Zookeeper |
| 配置中心 | 统一管理配置 | Spring Cloud Config |
| 消息中间件 | 异步通信 | RabbitMQ, Kafka |
| 分布式追踪系统 | 请求链路追踪 | Jaeger, Zipkin |
第十部分:前端集成与全栈实践
10.1 Swagger API文档集成
步骤1:安装依赖
npm install @nestjs/swagger swagger-ui-express
步骤2:配置Swagger模块
// main.ts
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';async function bootstrap() {const app = await NestFactory.create(AppModule);const config = new DocumentBuilder().setTitle('NestJS API').setDescription('全栈开发接口文档').setVersion('1.0').addBearerAuth() // 启用JWT认证.build();const document = SwaggerModule.createDocument(app, config);SwaggerModule.setup('api-docs', app, document);await app.listen(3000);
}
步骤3:添加接口注释
// user.controller.ts
@ApiOperation({ summary: '获取用户列表' })
@ApiResponse({ status: 200, description: '返回用户数组' })
@Get()
getAllUsers() {return this.userService.findAll();
}// create-user.dto.ts
export class CreateUserDto {@ApiProperty({ example: '张三', description: '用户姓名' })@IsString()name: string;
}
访问文档:http://localhost:3000/api-docs
10.2 前端项目配置(以React为例)
步骤1:创建React应用
npx create-react-app nest-client
cd nest-client
步骤2:配置代理(解决跨域)
// package.json
{"proxy": "http://localhost:3000"
}
步骤3:安装axios
npm install axios
10.3 实现登录认证流程
// src/api/auth.js
import axios from 'axios';export const login = async (credentials) => {const response = await axios.post('/auth/login', credentials);localStorage.setItem('access_token', response.data.access_token);return response.data;
};export const getProfile = async () => {return axios.get('/users/profile', {headers: {Authorization: `Bearer ${localStorage.getItem('access_token')}`}});
};
10.4 前端路由保护(React示例)
// src/components/PrivateRoute.js
import { Navigate } from 'react-router-dom';const PrivateRoute = ({ children }) => {const isAuthenticated = !!localStorage.getItem('access_token');return isAuthenticated ? children : <Navigate to="/login" />;
};
10.5 全栈调试技巧
调试工具组合:
常见问题排查:
-
跨域问题:
// 后端启用CORS app.enableCors({origin: 'http://localhost:3001',methods: 'GET,HEAD,PUT,PATCH,POST,DELETE',credentials: true, }); -
认证失效处理:
// 前端axios拦截器 axios.interceptors.response.use(response => response,error => {if (error.response.status === 401) {window.location = '/login';}return Promise.reject(error);} );
10.6 部署联调配置
生产环境配置示例:
# nginx配置
server {listen 80;server_name yourdomain.com;location /api {proxy_pass http://backend:3000;proxy_set_header Host $host;}location / {root /var/www/client;try_files $uri $uri/ /index.html;}
}
全栈开发关键点总结
| 层级 | 技术栈 | 关注重点 |
|---|---|---|
| 前端 | React/Vue + Axios | 状态管理、路由守卫 |
| 网关层 | Nginx | 负载均衡、HTTPS配置 |
| 后端 | NestJS + TypeORM | 业务逻辑、数据库优化 |
| 基础设施 | Docker + PostgreSQL | 容器编排、备份策略 |
项目完整工作流
至此,Nest.js全栈开发系列教程已全部完成!建议学习者通过以下方式巩固知识:
- 开发一个完整博客系统(包含用户/文章/评论模块)
- 尝试部署到云平台(AWS/Aliyun)
- 参与开源Nest.js项目
- 探索NestJS官方高级特性(CLI插件、自定义装饰器等)
相关文章:
Nest.js全栈开发终极实践:TypeORM+微服务+Docker构建高可用企业级应用
文章目录 **第一部分:认识Nest.js与基础环境搭建****1.1 什么是Nest.js?****1.2 环境准备****1.3 创建第一个项目****1.4 启动开发服务器****1.5 核心文件解读** **第二部分:基础控制器与路由****2.1 控制器的作用****2.2 创建自定义控制器**…...
Go语言集成DeepSeek API和GoFly框架文本编辑器实现流式输出和对话(GoFly快速开发框架)
说明 本文是GoFly快速开发框架集成Go语言调用 DeepSeek API 插件,实现流式输出和对话功能。为了方便实现更多业务功能我们在Go服务端调用AI即DeepSeek接口,处理好业务后再用Gin框架实现流失流式输出到前端,前端使用fetch请求接收到流式的mar…...
Hexo博客Icarus主题不蒜子 UV、PV 统计数据初始化配置
文章首发于 不蒜子 UV、PV 统计数据初始化配置 适用场景 如果你有个运行的网站域名,采用了不蒜子统计 UV、PV等访客和阅读数据,但是有一天,你觉得想要换一个新的域名。当你将网站绑定到新的域名后,突然发现,所有的文章…...
在资源有限中逆势突围:从抗战智谋到寒门高考的破局智慧
目录 引言 一、历史中的非对称作战:从李牧到八路军的智谋传承 李牧戍边:古代军事博弈中的资源重构 八路军的游击战:现代战争中的智慧延续 二、创业界的逆袭之道:小米与拼多多的资源重构 从MVP到杠杆解 社交裂变与资源错配 …...
SQLAlchemy系列教程:如何执行原生SQL
Python中的数据库交互提供了高级API。但是,有时您可能需要执行原始SQL以提高效率或利用数据库特定的特性。本指南介绍在SQLAlchemy框架内执行原始SQL。 在SQLAlchemy中执行原生SQL SQLAlchemy虽然以其对象-关系映射(ORM)功能而闻名ÿ…...
绪论数据结构基本概念(刷题笔记)
(一)单选题 1.与数据元素本身的形式、相对位置和个数无关的是(B)【广东工业大学2019年829数据结构】 A.数据存储结构 B.数据逻辑结构 C.算法 D.操作 2.在数据结构的讨论中把数据结构从逻辑上分为(C)【中国…...
delphi 正则提取html中的内容
function ExtractTextFromHTML(const HTML: string): string; var RegEx: TRegEx; begin Result := HTML; // 移除<script>标签及其内容 Result := TRegEx.Replace(Result, <script.*?>.*?</script>, , [roIgnoreCase, roSingleLine]); // 移除<s…...
18天 - 常见的 HTTP 状态码有哪些?HTTP 请求包含哪些内容,请求头和请求体有哪些类型?HTTP 中 GET 和 POST 的区别是什么?
常见的 HTTP 状态码有哪些? HTTP 状态码用于指示服务器对客户端请求的响应结果,常见的 HTTP 状态码可以分为以下几类: 1. 信息类(1xx) 100 Continue:客户端应继续发送请求。101 Switching Protocols&…...
从0开始的操作系统手搓教程45——实现exec
目录 建立抽象 实现加载 实现sys_execv !!!提示:因为实现问题没有测试。所以更像是笔记! exec 函数的作用是用新的可执行文件替换当前进程的程序体。具体来说,exec 会将当前正在运行的用户进程的进程体&…...
Android TCP封装工具类
TCP通信的封装,我们可以从以下几个方面进行改进: 线程池优化:使用更高效的线程池配置,避免频繁创建和销毁线程。 连接重试机制:在网络不稳定时,自动重试连接。 心跳机制:保持长连接ÿ…...
解决火绒启动时,报安全服务异常,无法保障计算机安全
1.找到控制面板-安全和维护-更改用户账户控制设置 重启启动电脑解决。...
Spring Boot框架总结(超级详细)
前言 本篇文章包含Springboot配置文件解释、热部署、自动装配原理源码级剖析、内嵌tomcat源码级剖析、缓存深入、多环境部署等等,如果能耐心看完,想必会有不少收获。 一、Spring Boot基础应用 Spring Boot特征 概念: 约定优于配置&#…...
为什么要使用前缀索引,以及建立前缀索引:sql示例
背景: 你想啊,数据库里有些字段,它老长了,就像那种 varchar(255) 的字段,这玩意儿要是整个字段都拿来建索引,那可太占地方了。打个比方,这就好比你要在一个超级大的笔记本上记东西,每…...
Nuxt3 ssr build/dev时区分不同的环境
package.json "scripts": {"build": "nuxt build --dotenv .env.prod","build:dev": "nuxt build --dotenv .env.dev","postbuild": "mv -f .output ./dist/.output", //支持自定义文件名"dev&quo…...
嵌入式学习第二十四天--网络 服务器
服务器模型 tcp服务器: socket bind listen accept recv/send close 1.支持多客户端访问 //单循环服务器 socket bind listen while(1) { accept while(1) { recv/send } } close 2.支持多客户端同时访问 (并发能力) 并发服务器 socket bind …...
tcp/ip协议配置参数有哪些?tcp/ip协议需要设置的参数有哪些
TCP/IP协议的配置参数是确保网络设备能够正确接入互联网并与其他设备进行通信的关键设置。这些参数主要包括以下几个方面: 1. IP地址 定义:IP地址是网络中设备的唯一标识符,用于标识和定位设备。它由32位二进制数组成,通常采用点…...
我有点担心开始AI中台了
有个特点历史教训是很难吸取的 从大数据开始就是一窝蜂的去搞,不管有没有什么数据量。反正要来个Hadoop。其实有些企业数据一块硬盘都放得下。 微服务来了,也不管自己的系统是不是适合微服务。我个人经验得出,to B和to G的业务场景…...
《用Python+PyGame开发双人生存游戏!源码解析+完整开发思路分享》
导语 "你是否想过用Python开发一款可玩性高的双人合作游戏?本文将分享如何从零开始实现一款类《吸血鬼幸存者》的生存射击游戏!包含完整源码解析、角色系统设计、敌人AI逻辑等核心技术点,文末提供完整代码包下载!" 哈…...
优选算法系列(1. 双指针_上)
目录 双指针 一:移动零(easy) 题目链接:移动零 解法: 代码: 二:复写零(easy) 题目链接:复写零 编辑 解法: 代码: 三:快乐…...
永洪科技深度分析实战,零售企业的销量预测
随着人工智能技术的不断发展,智能预测已经成为各个领域的重要应用之一。现在,智能预测技术已经广泛应用于金融、零售、医疗、能源等领域,为企业和个人提供决策支持。 智能预测技术通过分析大量的数据,利用机器学习和深度学习算法…...
XCTF-web-easyupload
试了试php,php7,pht,phtml等,都没有用 尝试.user.ini 抓包修改将.user.ini修改为jpg图片 在上传一个123.jpg 用蚁剑连接,得到flag...
label-studio的使用教程(导入本地路径)
文章目录 1. 准备环境2. 脚本启动2.1 Windows2.2 Linux 3. 安装label-studio机器学习后端3.1 pip安装(推荐)3.2 GitHub仓库安装 4. 后端配置4.1 yolo环境4.2 引入后端模型4.3 修改脚本4.4 启动后端 5. 标注工程5.1 创建工程5.2 配置图片路径5.3 配置工程类型标签5.4 配置模型5.…...
Python爬虫实战:研究feedparser库相关技术
1. 引言 1.1 研究背景与意义 在当今信息爆炸的时代,互联网上存在着海量的信息资源。RSS(Really Simple Syndication)作为一种标准化的信息聚合技术,被广泛用于网站内容的发布和订阅。通过 RSS,用户可以方便地获取网站更新的内容,而无需频繁访问各个网站。 然而,互联网…...
Leetcode 3577. Count the Number of Computer Unlocking Permutations
Leetcode 3577. Count the Number of Computer Unlocking Permutations 1. 解题思路2. 代码实现 题目链接:3577. Count the Number of Computer Unlocking Permutations 1. 解题思路 这一题其实就是一个脑筋急转弯,要想要能够将所有的电脑解锁&#x…...
[ICLR 2022]How Much Can CLIP Benefit Vision-and-Language Tasks?
论文网址:pdf 英文是纯手打的!论文原文的summarizing and paraphrasing。可能会出现难以避免的拼写错误和语法错误,若有发现欢迎评论指正!文章偏向于笔记,谨慎食用 目录 1. 心得 2. 论文逐段精读 2.1. Abstract 2…...
Mac软件卸载指南,简单易懂!
刚和Adobe分手,它却总在Library里给你写"回忆录"?卸载的Final Cut Pro像电子幽灵般阴魂不散?总是会有残留文件,别慌!这份Mac软件卸载指南,将用最硬核的方式教你"数字分手术"࿰…...
C# 类和继承(抽象类)
抽象类 抽象类是指设计为被继承的类。抽象类只能被用作其他类的基类。 不能创建抽象类的实例。抽象类使用abstract修饰符声明。 抽象类可以包含抽象成员或普通的非抽象成员。抽象类的成员可以是抽象成员和普通带 实现的成员的任意组合。抽象类自己可以派生自另一个抽象类。例…...
PL0语法,分析器实现!
简介 PL/0 是一种简单的编程语言,通常用于教学编译原理。它的语法结构清晰,功能包括常量定义、变量声明、过程(子程序)定义以及基本的控制结构(如条件语句和循环语句)。 PL/0 语法规范 PL/0 是一种教学用的小型编程语言,由 Niklaus Wirth 设计,用于展示编译原理的核…...
DeepSeek 技术赋能无人农场协同作业:用 AI 重构农田管理 “神经网”
目录 一、引言二、DeepSeek 技术大揭秘2.1 核心架构解析2.2 关键技术剖析 三、智能农业无人农场协同作业现状3.1 发展现状概述3.2 协同作业模式介绍 四、DeepSeek 的 “农场奇妙游”4.1 数据处理与分析4.2 作物生长监测与预测4.3 病虫害防治4.4 农机协同作业调度 五、实际案例大…...
代码随想录刷题day30
1、零钱兑换II 给你一个整数数组 coins 表示不同面额的硬币,另给一个整数 amount 表示总金额。 请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额,返回 0 。 假设每一种面额的硬币有无限个。 题目数据保证结果符合 32 位带…...
