Files
bw-mini-app-server/src/utils/response.util.ts
imeepos 4cb6b63948 feat: 修复抖音图片审核失败并设计统一异步架构
解决抖音图片审核"无效图片URL"问题,并设计统一异步架构方案:

## 核心修复
- 增强 validateImageUrl 方法,支持文件扩展名 + Content-Type 双重验证
- 修复抖音审核失败问题:binary/octet-stream 响应头导致的验证失败

## 架构设计
- 设计统一异步内容审核架构,抹平平台差异(同步/异步)
- 创建 EnhancedBaseContentAdapter 统一接口
- 实现平台适配器模式,WeChat同步转异步,Douyin原生异步
- 添加回调驱动的模板执行流程

## 数据库增强
- 新增 taskId 字段关联审核任务和模板执行
- 添加 PENDING_AUDIT 状态支持异步审核流程
- 创建 MySQL 优化的数据库迁移脚本

## 文档完善
- 更新内容审核设计文档,包含详细序列图
- 创建 5 阶段升级文档,含 MySQL 专项优化
- 提供完整的向后兼容迁移方案

## 测试改进
- 更新单元测试,修复 validateStatus 参数
- 增强错误处理和边界情况测试覆盖
2025-09-05 16:08:45 +08:00

103 lines
2.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { HttpStatus } from '@nestjs/common';
import * as crypto from 'crypto';
/**
* 统一响应格式工具类
* 规范化API响应结构提供一致的响应格式
*/
export interface ApiResponse<T = any> {
code: number;
message: string;
data?: T;
timestamp: number;
traceId: string;
}
export class ResponseUtil {
/**
* 生成追踪ID
* @returns 随机字符串
*/
private static generateTraceId(): string {
return crypto.randomUUID();
}
/**
* 成功响应
* @param data 响应数据
* @param message 响应消息
* @param code HTTP状态码
* @returns 标准化成功响应
*/
static success<T>(
data?: T,
message: string = 'success',
code: number = HttpStatus.OK,
): ApiResponse<T> {
return {
code,
message,
data,
timestamp: Date.now(),
traceId: this.generateTraceId(),
};
}
/**
* 错误响应(一般不直接使用,通过异常处理器处理)
* @param message 错误消息
* @param code HTTP状态码
* @returns 标准化错误响应
*/
static error(
message: string = 'Internal Server Error',
code: number = HttpStatus.INTERNAL_SERVER_ERROR,
): ApiResponse<null> {
return {
code,
message,
data: null,
timestamp: Date.now(),
traceId: this.generateTraceId(),
};
}
/**
* 分页响应
* @param items 数据项
* @param total 总数
* @param page 当前页
* @param limit 每页数量
* @param message 响应消息
* @returns 标准化分页响应
*/
static paginated<T>(
items: T[],
total: number,
page: number,
limit: number,
message: string = 'success',
): ApiResponse<{
items: T[];
pagination: {
total: number;
page: number;
limit: number;
totalPages: number;
};
}> {
return this.success(
{
items,
pagination: {
total,
page,
limit,
totalPages: Math.ceil(total / limit),
},
},
message,
);
}
}