feat(reset): 以构造器模式重构
- 加了大文件传输自定义分片协议 BREAKING CHANGES: 0.1.0(latest)
This commit is contained in:
132
api/upload-api.ts
Normal file
132
api/upload-api.ts
Normal file
@@ -0,0 +1,132 @@
|
||||
import { ApiClientBound } from '../decorators';
|
||||
import { API_ENDPOINTS } from './common';
|
||||
import type {
|
||||
UploadChunkRequest,
|
||||
UploadChunkResponse,
|
||||
MergeChunksRequest,
|
||||
MergeChunksResponse,
|
||||
CheckUploadStatusRequest,
|
||||
CheckUploadStatusResponse
|
||||
} from '../types/upload/api';
|
||||
import type { AxiosHttpClient } from '../client';
|
||||
|
||||
/**
|
||||
* 上传API服务类
|
||||
* 使用自定义实现而非@Request装饰器,以支持分片上传的复杂headers
|
||||
*/
|
||||
@ApiClientBound
|
||||
export class UploadApiService {
|
||||
/**
|
||||
* 客户端实例,由ApiClientBound装饰器注入
|
||||
*/
|
||||
declare client: AxiosHttpClient;
|
||||
|
||||
/**
|
||||
* 上传文件分片
|
||||
* @param chunkRequest 分片上传请求参数
|
||||
* @param chunkBlob 文件分片数据
|
||||
* @returns 分片上传响应
|
||||
*/
|
||||
async uploadChunk(
|
||||
chunkRequest: UploadChunkRequest,
|
||||
chunkBlob: Blob
|
||||
): Promise<UploadChunkResponse> {
|
||||
// 创建FormData以支持文件上传
|
||||
const formData = new FormData();
|
||||
formData.append('chunk', chunkBlob);
|
||||
formData.append('chunkIndex', chunkRequest.chunkIndex.toString());
|
||||
formData.append('totalChunks', chunkRequest.totalChunks.toString());
|
||||
formData.append('fileName', chunkRequest.fileName);
|
||||
formData.append('fileType', chunkRequest.fileType);
|
||||
formData.append('fileId', chunkRequest.fileId);
|
||||
|
||||
// 自定义headers,不设置Content-Type,让浏览器自动设置multipart/form-data
|
||||
const headers = {
|
||||
'X-Chunk-Index': chunkRequest.chunkIndex.toString(),
|
||||
'X-Total-Chunks': chunkRequest.totalChunks.toString(),
|
||||
'X-File-Id': chunkRequest.fileId,
|
||||
'X-Chunk-Size': chunkRequest.chunkSize.toString(),
|
||||
'X-Total-Size': chunkRequest.totalSize.toString(),
|
||||
// 不设置Content-Type,让浏览器自动处理
|
||||
};
|
||||
|
||||
// 直接使用client实例发送请求,而不通过@Request装饰器
|
||||
return await this.client.request({
|
||||
method: 'POST',
|
||||
url: API_ENDPOINTS.UPLOAD_CHUNK,
|
||||
body: formData,
|
||||
headers,
|
||||
// 允许跨域携带凭证
|
||||
withCredentials: true,
|
||||
// 禁用默认的Content-Type设置(禁止axios的jsonify处理)
|
||||
transformRequest: [(data: any) => data]
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 合并文件分片
|
||||
* @param mergeRequest 合并分片请求参数
|
||||
* @returns 合并分片响应
|
||||
*/
|
||||
async mergeChunks(mergeRequest: MergeChunksRequest): Promise<MergeChunksResponse> {
|
||||
const headers = {
|
||||
'Content-Type': 'application/json',
|
||||
'X-File-Id': mergeRequest.fileId,
|
||||
'X-Total-Chunks': mergeRequest.totalChunks.toString()
|
||||
};
|
||||
|
||||
return await this.client.request({
|
||||
method: 'POST',
|
||||
url: API_ENDPOINTS.MERGE_CHUNKS,
|
||||
body: mergeRequest,
|
||||
headers,
|
||||
withCredentials: true
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查文件上传状态
|
||||
* @param checkRequest 检查上传状态请求参数
|
||||
* @returns 上传状态响应
|
||||
*/
|
||||
async checkUploadStatus(
|
||||
checkRequest: CheckUploadStatusRequest
|
||||
): Promise<CheckUploadStatusResponse> {
|
||||
const headers = {
|
||||
'X-File-Id': checkRequest.fileId
|
||||
};
|
||||
|
||||
return await this.client.request({
|
||||
method: 'POST',
|
||||
url: API_ENDPOINTS.CHECK_UPLOAD_STATUS,
|
||||
body: checkRequest,
|
||||
headers,
|
||||
withCredentials: true
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成文件唯一ID
|
||||
* @param _fileName 文件名(未使用,保留参数位置)
|
||||
* @param fileSize 文件大小
|
||||
* @returns 文件唯一ID
|
||||
*/
|
||||
generateFileId(_fileName: string, fileSize: number): string {
|
||||
const timestamp = Date.now().toString(36);
|
||||
const random = Math.random().toString(36).substring(2, 9);
|
||||
return `${timestamp}_${random}_${fileSize}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算分片数量
|
||||
* @param fileSize 文件大小
|
||||
* @param chunkSize 分片大小
|
||||
* @returns 分片数量
|
||||
*/
|
||||
calculateChunks(fileSize: number, chunkSize: number = 5 * 1024 * 1024): number {
|
||||
return Math.ceil(fileSize / chunkSize);
|
||||
}
|
||||
}
|
||||
|
||||
// 导出单例实例
|
||||
export const uploadApi = new UploadApiService();
|
||||
Reference in New Issue
Block a user