feat: 适配新uploadFn,并修复小程序端使用PUT的错误判断
This commit is contained in:
parent
56b07dc4cb
commit
95b506b0eb
|
|
@ -1,11 +1,8 @@
|
||||||
import { EntityDict } from '../oak-app-domain';
|
import { EntityDict } from '../oak-app-domain';
|
||||||
import { BRC } from '..';
|
import { BRC } from '..';
|
||||||
import { Cache } from 'oak-frontend-base/es/features/cache';
|
import { Cache } from 'oak-frontend-base/es/features/cache';
|
||||||
export type UploadFn = (file: File | string | Blob, name: string, // 文件的part name
|
import { UploadInterface } from 'oak-frontend-base/es/types/Upload';
|
||||||
uploadUrl: string, // 上传的url
|
export type UploadFn = UploadInterface['uploadFile'];
|
||||||
formData: Record<string, any>, // 上传的其它part参数
|
|
||||||
autoInform?: boolean, // 上传成功是否会自动通知server(若不会则需要前台显式通知
|
|
||||||
getPercent?: Function, uploadId?: string, method?: "POST" | "PUT") => Promise<any>;
|
|
||||||
export type UploadToAspect = (file: File | string, name: string, // 文件的part name
|
export type UploadToAspect = (file: File | string, name: string, // 文件的part name
|
||||||
aspectName: string, // 上传的aspect名
|
aspectName: string, // 上传的aspect名
|
||||||
formData: Record<string, any>, // 上传的其它part参数
|
formData: Record<string, any>, // 上传的其它part参数
|
||||||
|
|
|
||||||
|
|
@ -43,12 +43,20 @@ export default class ALiYun {
|
||||||
else {
|
else {
|
||||||
let response;
|
let response;
|
||||||
try {
|
try {
|
||||||
response = await uploadFn(file, 'file', uploadMeta.uploadHost, {
|
response = await uploadFn({
|
||||||
key: uploadMeta.key,
|
file: file,
|
||||||
policy: uploadMeta.policy,
|
name: 'file',
|
||||||
ossAccessKeyId: uploadMeta.accessKey,
|
uploadUrl: uploadMeta.uploadHost,
|
||||||
signature: uploadMeta.signature,
|
formData: {
|
||||||
}, true, getPercent, extraFile.id);
|
key: uploadMeta.key,
|
||||||
|
policy: uploadMeta.policy,
|
||||||
|
ossAccessKeyId: uploadMeta.accessKey,
|
||||||
|
signature: uploadMeta.signature,
|
||||||
|
},
|
||||||
|
autoInform: true,
|
||||||
|
getPercent,
|
||||||
|
uploadId: extraFile.id,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
catch (err) {
|
catch (err) {
|
||||||
// 网络错误
|
// 网络错误
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
import { sliceFile, cleanTempFiles } from '../files/slice';
|
import { sliceFile } from '../files/slice';
|
||||||
import assert from 'assert';
|
|
||||||
import { OakUploadException } from '../../types/Exception';
|
import { OakUploadException } from '../../types/Exception';
|
||||||
export function isAbortError(error) {
|
export function isAbortError(error) {
|
||||||
return error instanceof DOMException && error.name === 'AbortError';
|
return error instanceof DOMException && error.name === 'AbortError';
|
||||||
|
|
@ -37,25 +36,33 @@ export async function chunkUpload(options) {
|
||||||
let lastError;
|
let lastError;
|
||||||
for (let attempt = 0; attempt <= retryTimes; attempt++) {
|
for (let attempt = 0; attempt <= retryTimes; attempt++) {
|
||||||
try {
|
try {
|
||||||
const response = await uploadFn(chunk, 'file', part.uploadUrl, part.formData || {}, true, (percent) => {
|
let data;
|
||||||
// 更新每个分片的进度
|
if (chunk.type === 'getter') {
|
||||||
updateChunkPercent(part.partNumber, percent);
|
data = await chunk.getFile();
|
||||||
}, `${extraFile.id}:${part.partNumber}`, "PUT");
|
|
||||||
// 验证上传是否成功
|
|
||||||
let isSuccess = false;
|
|
||||||
if (process.env.OAK_PLATFORM === 'wechatMp') {
|
|
||||||
if (response.errMsg === 'request:ok') {
|
|
||||||
const data = JSON.parse(response.data);
|
|
||||||
isSuccess = !!(data.status === 204 || data.status === 200);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
isSuccess = !!(response.status === 200 || response.status === 204);
|
data = chunk;
|
||||||
}
|
}
|
||||||
|
const response = await uploadFn({
|
||||||
|
file: data,
|
||||||
|
name: 'file',
|
||||||
|
uploadUrl: part.uploadUrl,
|
||||||
|
formData: part.formData || {},
|
||||||
|
autoInform: true,
|
||||||
|
getPercent: (percent) => {
|
||||||
|
// 更新每个分片的进度
|
||||||
|
updateChunkPercent(part.partNumber, percent);
|
||||||
|
},
|
||||||
|
uploadId: `${extraFile.id}:${part.partNumber}`,
|
||||||
|
method: "PUT"
|
||||||
|
});
|
||||||
|
// 验证上传是否成功
|
||||||
|
let isSuccess = false;
|
||||||
|
isSuccess = !!(response.status === 200 || response.status === 204);
|
||||||
if (isSuccess) {
|
if (isSuccess) {
|
||||||
// 标记该分片已完成
|
// // 标记该分片已完成
|
||||||
part.etag = response.headers?.get("ETag") || response.headers?.get("etag") || response.headers?.get("eTag");
|
// part.etag = (response as Response).headers?.get("ETag") || response.headers?.get("etag") || response.headers?.get("eTag")
|
||||||
assert(part.etag, `无法获取分片 ${part.partNumber} 的 ETag`);
|
// assert(part.etag, `无法获取分片 ${part.partNumber} 的 ETag`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
throw new OakUploadException(`分片 ${part.partNumber} 上传失败`);
|
throw new OakUploadException(`分片 ${part.partNumber} 上传失败`);
|
||||||
|
|
@ -122,9 +129,5 @@ export async function chunkUpload(options) {
|
||||||
// if (onChunkSuccess) {
|
// if (onChunkSuccess) {
|
||||||
// await onChunkSuccess(chunkInfo);
|
// await onChunkSuccess(chunkInfo);
|
||||||
// }
|
// }
|
||||||
// 清理小程序环境下的临时文件
|
|
||||||
if (process.env.OAK_PLATFORM === 'wechatMp' && typeof file === 'string') {
|
|
||||||
await cleanTempFiles(chunks);
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,12 +30,20 @@ export default class CTYun {
|
||||||
assert(extraFile.enableChunkedUpload !== true, '天翼云暂不支持分片上传');
|
assert(extraFile.enableChunkedUpload !== true, '天翼云暂不支持分片上传');
|
||||||
let response;
|
let response;
|
||||||
try {
|
try {
|
||||||
response = await uploadFn(file, 'file', uploadMeta.uploadHost, {
|
response = await uploadFn({
|
||||||
key: uploadMeta.key,
|
file: file,
|
||||||
Policy: uploadMeta.policy,
|
name: 'file',
|
||||||
AWSAccessKeyId: uploadMeta.accessKey,
|
uploadUrl: uploadMeta.uploadHost,
|
||||||
signature: uploadMeta.signature,
|
formData: {
|
||||||
}, true, getPercent, extraFile.id);
|
key: uploadMeta.key,
|
||||||
|
Policy: uploadMeta.policy,
|
||||||
|
AWSAccessKeyId: uploadMeta.accessKey,
|
||||||
|
signature: uploadMeta.signature,
|
||||||
|
},
|
||||||
|
autoInform: true,
|
||||||
|
getPercent,
|
||||||
|
uploadId: extraFile.id,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
catch (err) {
|
catch (err) {
|
||||||
// 网络错误
|
// 网络错误
|
||||||
|
|
|
||||||
|
|
@ -30,10 +30,18 @@ export default class Qiniu {
|
||||||
assert(extraFile.enableChunkedUpload !== true, '暂不支持分片上传');
|
assert(extraFile.enableChunkedUpload !== true, '暂不支持分片上传');
|
||||||
let response;
|
let response;
|
||||||
try {
|
try {
|
||||||
response = await uploadFn(file, 'file', uploadMeta.uploadHost, {
|
response = await uploadFn({
|
||||||
key: uploadMeta.key,
|
file,
|
||||||
token: uploadMeta.uploadToken,
|
name: 'file',
|
||||||
}, true, getPercent, extraFile.id);
|
uploadUrl: uploadMeta.uploadHost,
|
||||||
|
formData: {
|
||||||
|
key: uploadMeta.key,
|
||||||
|
token: uploadMeta.uploadToken,
|
||||||
|
},
|
||||||
|
autoInform: true,
|
||||||
|
getPercent,
|
||||||
|
uploadId: extraFile.id,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
catch (err) {
|
catch (err) {
|
||||||
// 网络错误
|
// 网络错误
|
||||||
|
|
|
||||||
|
|
@ -46,22 +46,23 @@ export default class S3 {
|
||||||
let response;
|
let response;
|
||||||
try {
|
try {
|
||||||
// S3 使用预签名 URL 直接上传,不需要额外的 formData
|
// S3 使用预签名 URL 直接上传,不需要额外的 formData
|
||||||
response = await uploadFn(file, 'file', uploadMeta.uploadUrl, {}, true, getPercent, extraFile.id, "PUT");
|
response = await uploadFn({
|
||||||
|
file,
|
||||||
|
name: 'file',
|
||||||
|
uploadUrl: uploadMeta.uploadUrl,
|
||||||
|
formData: {},
|
||||||
|
autoInform: true,
|
||||||
|
getPercent,
|
||||||
|
uploadId: extraFile.id,
|
||||||
|
method: "PUT",
|
||||||
|
isFilePath: true,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
catch (err) {
|
catch (err) {
|
||||||
throw new OakNetworkException('网络异常,请求失败');
|
throw new OakNetworkException('网络异常,请求失败');
|
||||||
}
|
}
|
||||||
let isSuccess = false;
|
let isSuccess = false;
|
||||||
if (process.env.OAK_PLATFORM === 'wechatMp') {
|
isSuccess = response.status === 200 || response.status === 204;
|
||||||
// 小程序端上传
|
|
||||||
if (response.errMsg === 'uploadFile:ok') {
|
|
||||||
const statusCode = response.statusCode;
|
|
||||||
isSuccess = statusCode === 200 || statusCode === 204;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
isSuccess = response.status === 200 || response.status === 204;
|
|
||||||
}
|
|
||||||
if (isSuccess) {
|
if (isSuccess) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,15 +31,23 @@ export default class TencentYun {
|
||||||
assert(extraFile.enableChunkedUpload !== true, '暂不支持分片上传');
|
assert(extraFile.enableChunkedUpload !== true, '暂不支持分片上传');
|
||||||
let response;
|
let response;
|
||||||
try {
|
try {
|
||||||
response = await uploadFn(file, 'file', uploadMeta.uploadHost, {
|
response = await uploadFn({
|
||||||
key: uploadMeta.key,
|
file,
|
||||||
policy: uploadMeta.policy,
|
name: 'file',
|
||||||
signature: uploadMeta.signature,
|
uploadUrl: uploadMeta.uploadHost,
|
||||||
'q-sign-algorithm': uploadMeta.algorithm,
|
formData: {
|
||||||
'q-ak': uploadMeta.accessKey,
|
key: uploadMeta.key,
|
||||||
'q-key-time': uploadMeta.keyTime,
|
policy: uploadMeta.policy,
|
||||||
'q-signature': uploadMeta.signature,
|
signature: uploadMeta.signature,
|
||||||
}, true, getPercent, extraFile.id);
|
'q-sign-algorithm': uploadMeta.algorithm,
|
||||||
|
'q-ak': uploadMeta.accessKey,
|
||||||
|
'q-key-time': uploadMeta.keyTime,
|
||||||
|
'q-signature': uploadMeta.signature,
|
||||||
|
},
|
||||||
|
autoInform: true,
|
||||||
|
getPercent,
|
||||||
|
uploadId: extraFile.id
|
||||||
|
});
|
||||||
}
|
}
|
||||||
catch (err) {
|
catch (err) {
|
||||||
// 网络错误
|
// 网络错误
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,7 @@
|
||||||
export declare function sliceFile(file: string | File, chunkSize: number, partCount: number): Promise<(File | Blob | string)[]>;
|
export type MpFileGetter = {
|
||||||
export declare function sliceFileForMp(filePath: string, chunkSize: number, partCount: number): Promise<string[]>;
|
type: 'getter';
|
||||||
|
getFile: () => Promise<string | ArrayBuffer>;
|
||||||
|
};
|
||||||
|
export declare function sliceFile(file: string | File, chunkSize: number, partCount: number): Promise<(File | Blob | MpFileGetter)[]>;
|
||||||
|
export declare function sliceFileForMp(filePath: string, chunkSize: number, partCount: number): Promise<MpFileGetter[]>;
|
||||||
export declare function cleanTempFiles(tempFiles: string[]): Promise<void>;
|
export declare function cleanTempFiles(tempFiles: string[]): Promise<void>;
|
||||||
|
|
|
||||||
|
|
@ -42,34 +42,17 @@ export async function sliceFileForMp(filePath, chunkSize, partCount) {
|
||||||
const start = i * chunkSize;
|
const start = i * chunkSize;
|
||||||
const length = Math.min(chunkSize, fileSize - start);
|
const length = Math.min(chunkSize, fileSize - start);
|
||||||
try {
|
try {
|
||||||
// 读取分片数据
|
chunks.push({
|
||||||
const data = await new Promise((resolve, reject) => {
|
type: 'getter',
|
||||||
fs.readFile({
|
getFile: async () => {
|
||||||
filePath: filePath,
|
// 读取分片数据
|
||||||
encoding: 'binary',
|
const data = fs.readFileSync(filePath, 'binary', start, length);
|
||||||
position: start,
|
return data;
|
||||||
length: length,
|
}
|
||||||
success: (res) => resolve(res.data),
|
|
||||||
fail: reject
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
// 写入临时文件
|
|
||||||
const tempFilePath = `${tempDir}/chunk_${Date.now()}_${i}.temp`;
|
|
||||||
await new Promise((resolve, reject) => {
|
|
||||||
fs.writeFile({
|
|
||||||
filePath: tempFilePath,
|
|
||||||
encoding: 'binary',
|
|
||||||
data: data,
|
|
||||||
success: () => resolve(),
|
|
||||||
fail: reject
|
|
||||||
});
|
|
||||||
});
|
|
||||||
chunks.push(tempFilePath);
|
|
||||||
}
|
}
|
||||||
catch (err) {
|
catch (err) {
|
||||||
console.error('分片读取失败:', err);
|
console.error('分片读取失败:', err);
|
||||||
// 清理已创建的临时文件
|
|
||||||
await cleanTempFiles(chunks);
|
|
||||||
throw new OakUploadException(`分片 ${i + 1} 读取失败: ${err}`);
|
throw new OakUploadException(`分片 ${i + 1} 读取失败: ${err}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,8 @@
|
||||||
import { EntityDict } from '../oak-app-domain';
|
import { EntityDict } from '../oak-app-domain';
|
||||||
import { BRC } from '..';
|
import { BRC } from '..';
|
||||||
import { Cache } from 'oak-frontend-base/es/features/cache';
|
import { Cache } from 'oak-frontend-base/es/features/cache';
|
||||||
export type UploadFn = (file: File | string | Blob, name: string, // 文件的part name
|
import { UploadInterface } from 'oak-frontend-base/es/types/Upload';
|
||||||
uploadUrl: string, // 上传的url
|
export type UploadFn = UploadInterface['uploadFile'];
|
||||||
formData: Record<string, any>, // 上传的其它part参数
|
|
||||||
autoInform?: boolean, // 上传成功是否会自动通知server(若不会则需要前台显式通知
|
|
||||||
getPercent?: Function, uploadId?: string, method?: "POST" | "PUT") => Promise<any>;
|
|
||||||
export type UploadToAspect = (file: File | string, name: string, // 文件的part name
|
export type UploadToAspect = (file: File | string, name: string, // 文件的part name
|
||||||
aspectName: string, // 上传的aspect名
|
aspectName: string, // 上传的aspect名
|
||||||
formData: Record<string, any>, // 上传的其它part参数
|
formData: Record<string, any>, // 上传的其它part参数
|
||||||
|
|
|
||||||
|
|
@ -45,12 +45,20 @@ class ALiYun {
|
||||||
else {
|
else {
|
||||||
let response;
|
let response;
|
||||||
try {
|
try {
|
||||||
response = await uploadFn(file, 'file', uploadMeta.uploadHost, {
|
response = await uploadFn({
|
||||||
key: uploadMeta.key,
|
file: file,
|
||||||
policy: uploadMeta.policy,
|
name: 'file',
|
||||||
ossAccessKeyId: uploadMeta.accessKey,
|
uploadUrl: uploadMeta.uploadHost,
|
||||||
signature: uploadMeta.signature,
|
formData: {
|
||||||
}, true, getPercent, extraFile.id);
|
key: uploadMeta.key,
|
||||||
|
policy: uploadMeta.policy,
|
||||||
|
ossAccessKeyId: uploadMeta.accessKey,
|
||||||
|
signature: uploadMeta.signature,
|
||||||
|
},
|
||||||
|
autoInform: true,
|
||||||
|
getPercent,
|
||||||
|
uploadId: extraFile.id,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
catch (err) {
|
catch (err) {
|
||||||
// 网络错误
|
// 网络错误
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,7 @@
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
exports.isAbortError = isAbortError;
|
exports.isAbortError = isAbortError;
|
||||||
exports.chunkUpload = chunkUpload;
|
exports.chunkUpload = chunkUpload;
|
||||||
const tslib_1 = require("tslib");
|
|
||||||
const slice_1 = require("../files/slice");
|
const slice_1 = require("../files/slice");
|
||||||
const assert_1 = tslib_1.__importDefault(require("assert"));
|
|
||||||
const Exception_1 = require("../../types/Exception");
|
const Exception_1 = require("../../types/Exception");
|
||||||
function isAbortError(error) {
|
function isAbortError(error) {
|
||||||
return error instanceof DOMException && error.name === 'AbortError';
|
return error instanceof DOMException && error.name === 'AbortError';
|
||||||
|
|
@ -42,25 +40,33 @@ async function chunkUpload(options) {
|
||||||
let lastError;
|
let lastError;
|
||||||
for (let attempt = 0; attempt <= retryTimes; attempt++) {
|
for (let attempt = 0; attempt <= retryTimes; attempt++) {
|
||||||
try {
|
try {
|
||||||
const response = await uploadFn(chunk, 'file', part.uploadUrl, part.formData || {}, true, (percent) => {
|
let data;
|
||||||
// 更新每个分片的进度
|
if (chunk.type === 'getter') {
|
||||||
updateChunkPercent(part.partNumber, percent);
|
data = await chunk.getFile();
|
||||||
}, `${extraFile.id}:${part.partNumber}`, "PUT");
|
|
||||||
// 验证上传是否成功
|
|
||||||
let isSuccess = false;
|
|
||||||
if (process.env.OAK_PLATFORM === 'wechatMp') {
|
|
||||||
if (response.errMsg === 'request:ok') {
|
|
||||||
const data = JSON.parse(response.data);
|
|
||||||
isSuccess = !!(data.status === 204 || data.status === 200);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
isSuccess = !!(response.status === 200 || response.status === 204);
|
data = chunk;
|
||||||
}
|
}
|
||||||
|
const response = await uploadFn({
|
||||||
|
file: data,
|
||||||
|
name: 'file',
|
||||||
|
uploadUrl: part.uploadUrl,
|
||||||
|
formData: part.formData || {},
|
||||||
|
autoInform: true,
|
||||||
|
getPercent: (percent) => {
|
||||||
|
// 更新每个分片的进度
|
||||||
|
updateChunkPercent(part.partNumber, percent);
|
||||||
|
},
|
||||||
|
uploadId: `${extraFile.id}:${part.partNumber}`,
|
||||||
|
method: "PUT"
|
||||||
|
});
|
||||||
|
// 验证上传是否成功
|
||||||
|
let isSuccess = false;
|
||||||
|
isSuccess = !!(response.status === 200 || response.status === 204);
|
||||||
if (isSuccess) {
|
if (isSuccess) {
|
||||||
// 标记该分片已完成
|
// // 标记该分片已完成
|
||||||
part.etag = response.headers?.get("ETag") || response.headers?.get("etag") || response.headers?.get("eTag");
|
// part.etag = (response as Response).headers?.get("ETag") || response.headers?.get("etag") || response.headers?.get("eTag")
|
||||||
(0, assert_1.default)(part.etag, `无法获取分片 ${part.partNumber} 的 ETag`);
|
// assert(part.etag, `无法获取分片 ${part.partNumber} 的 ETag`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
throw new Exception_1.OakUploadException(`分片 ${part.partNumber} 上传失败`);
|
throw new Exception_1.OakUploadException(`分片 ${part.partNumber} 上传失败`);
|
||||||
|
|
@ -127,9 +133,5 @@ async function chunkUpload(options) {
|
||||||
// if (onChunkSuccess) {
|
// if (onChunkSuccess) {
|
||||||
// await onChunkSuccess(chunkInfo);
|
// await onChunkSuccess(chunkInfo);
|
||||||
// }
|
// }
|
||||||
// 清理小程序环境下的临时文件
|
|
||||||
if (process.env.OAK_PLATFORM === 'wechatMp' && typeof file === 'string') {
|
|
||||||
await (0, slice_1.cleanTempFiles)(chunks);
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,12 +32,20 @@ class CTYun {
|
||||||
(0, assert_1.assert)(extraFile.enableChunkedUpload !== true, '天翼云暂不支持分片上传');
|
(0, assert_1.assert)(extraFile.enableChunkedUpload !== true, '天翼云暂不支持分片上传');
|
||||||
let response;
|
let response;
|
||||||
try {
|
try {
|
||||||
response = await uploadFn(file, 'file', uploadMeta.uploadHost, {
|
response = await uploadFn({
|
||||||
key: uploadMeta.key,
|
file: file,
|
||||||
Policy: uploadMeta.policy,
|
name: 'file',
|
||||||
AWSAccessKeyId: uploadMeta.accessKey,
|
uploadUrl: uploadMeta.uploadHost,
|
||||||
signature: uploadMeta.signature,
|
formData: {
|
||||||
}, true, getPercent, extraFile.id);
|
key: uploadMeta.key,
|
||||||
|
Policy: uploadMeta.policy,
|
||||||
|
AWSAccessKeyId: uploadMeta.accessKey,
|
||||||
|
signature: uploadMeta.signature,
|
||||||
|
},
|
||||||
|
autoInform: true,
|
||||||
|
getPercent,
|
||||||
|
uploadId: extraFile.id,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
catch (err) {
|
catch (err) {
|
||||||
// 网络错误
|
// 网络错误
|
||||||
|
|
|
||||||
|
|
@ -32,10 +32,18 @@ class Qiniu {
|
||||||
(0, assert_1.assert)(extraFile.enableChunkedUpload !== true, '暂不支持分片上传');
|
(0, assert_1.assert)(extraFile.enableChunkedUpload !== true, '暂不支持分片上传');
|
||||||
let response;
|
let response;
|
||||||
try {
|
try {
|
||||||
response = await uploadFn(file, 'file', uploadMeta.uploadHost, {
|
response = await uploadFn({
|
||||||
key: uploadMeta.key,
|
file,
|
||||||
token: uploadMeta.uploadToken,
|
name: 'file',
|
||||||
}, true, getPercent, extraFile.id);
|
uploadUrl: uploadMeta.uploadHost,
|
||||||
|
formData: {
|
||||||
|
key: uploadMeta.key,
|
||||||
|
token: uploadMeta.uploadToken,
|
||||||
|
},
|
||||||
|
autoInform: true,
|
||||||
|
getPercent,
|
||||||
|
uploadId: extraFile.id,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
catch (err) {
|
catch (err) {
|
||||||
// 网络错误
|
// 网络错误
|
||||||
|
|
|
||||||
|
|
@ -48,22 +48,23 @@ class S3 {
|
||||||
let response;
|
let response;
|
||||||
try {
|
try {
|
||||||
// S3 使用预签名 URL 直接上传,不需要额外的 formData
|
// S3 使用预签名 URL 直接上传,不需要额外的 formData
|
||||||
response = await uploadFn(file, 'file', uploadMeta.uploadUrl, {}, true, getPercent, extraFile.id, "PUT");
|
response = await uploadFn({
|
||||||
|
file,
|
||||||
|
name: 'file',
|
||||||
|
uploadUrl: uploadMeta.uploadUrl,
|
||||||
|
formData: {},
|
||||||
|
autoInform: true,
|
||||||
|
getPercent,
|
||||||
|
uploadId: extraFile.id,
|
||||||
|
method: "PUT",
|
||||||
|
isFilePath: true,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
catch (err) {
|
catch (err) {
|
||||||
throw new Exception_2.OakNetworkException('网络异常,请求失败');
|
throw new Exception_2.OakNetworkException('网络异常,请求失败');
|
||||||
}
|
}
|
||||||
let isSuccess = false;
|
let isSuccess = false;
|
||||||
if (process.env.OAK_PLATFORM === 'wechatMp') {
|
isSuccess = response.status === 200 || response.status === 204;
|
||||||
// 小程序端上传
|
|
||||||
if (response.errMsg === 'uploadFile:ok') {
|
|
||||||
const statusCode = response.statusCode;
|
|
||||||
isSuccess = statusCode === 200 || statusCode === 204;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
isSuccess = response.status === 200 || response.status === 204;
|
|
||||||
}
|
|
||||||
if (isSuccess) {
|
if (isSuccess) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,15 +33,23 @@ class TencentYun {
|
||||||
(0, assert_1.assert)(extraFile.enableChunkedUpload !== true, '暂不支持分片上传');
|
(0, assert_1.assert)(extraFile.enableChunkedUpload !== true, '暂不支持分片上传');
|
||||||
let response;
|
let response;
|
||||||
try {
|
try {
|
||||||
response = await uploadFn(file, 'file', uploadMeta.uploadHost, {
|
response = await uploadFn({
|
||||||
key: uploadMeta.key,
|
file,
|
||||||
policy: uploadMeta.policy,
|
name: 'file',
|
||||||
signature: uploadMeta.signature,
|
uploadUrl: uploadMeta.uploadHost,
|
||||||
'q-sign-algorithm': uploadMeta.algorithm,
|
formData: {
|
||||||
'q-ak': uploadMeta.accessKey,
|
key: uploadMeta.key,
|
||||||
'q-key-time': uploadMeta.keyTime,
|
policy: uploadMeta.policy,
|
||||||
'q-signature': uploadMeta.signature,
|
signature: uploadMeta.signature,
|
||||||
}, true, getPercent, extraFile.id);
|
'q-sign-algorithm': uploadMeta.algorithm,
|
||||||
|
'q-ak': uploadMeta.accessKey,
|
||||||
|
'q-key-time': uploadMeta.keyTime,
|
||||||
|
'q-signature': uploadMeta.signature,
|
||||||
|
},
|
||||||
|
autoInform: true,
|
||||||
|
getPercent,
|
||||||
|
uploadId: extraFile.id
|
||||||
|
});
|
||||||
}
|
}
|
||||||
catch (err) {
|
catch (err) {
|
||||||
// 网络错误
|
// 网络错误
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,7 @@
|
||||||
export declare function sliceFile(file: string | File, chunkSize: number, partCount: number): Promise<(File | Blob | string)[]>;
|
export type MpFileGetter = {
|
||||||
export declare function sliceFileForMp(filePath: string, chunkSize: number, partCount: number): Promise<string[]>;
|
type: 'getter';
|
||||||
|
getFile: () => Promise<string | ArrayBuffer>;
|
||||||
|
};
|
||||||
|
export declare function sliceFile(file: string | File, chunkSize: number, partCount: number): Promise<(File | Blob | MpFileGetter)[]>;
|
||||||
|
export declare function sliceFileForMp(filePath: string, chunkSize: number, partCount: number): Promise<MpFileGetter[]>;
|
||||||
export declare function cleanTempFiles(tempFiles: string[]): Promise<void>;
|
export declare function cleanTempFiles(tempFiles: string[]): Promise<void>;
|
||||||
|
|
|
||||||
|
|
@ -48,34 +48,17 @@ async function sliceFileForMp(filePath, chunkSize, partCount) {
|
||||||
const start = i * chunkSize;
|
const start = i * chunkSize;
|
||||||
const length = Math.min(chunkSize, fileSize - start);
|
const length = Math.min(chunkSize, fileSize - start);
|
||||||
try {
|
try {
|
||||||
// 读取分片数据
|
chunks.push({
|
||||||
const data = await new Promise((resolve, reject) => {
|
type: 'getter',
|
||||||
fs.readFile({
|
getFile: async () => {
|
||||||
filePath: filePath,
|
// 读取分片数据
|
||||||
encoding: 'binary',
|
const data = fs.readFileSync(filePath, 'binary', start, length);
|
||||||
position: start,
|
return data;
|
||||||
length: length,
|
}
|
||||||
success: (res) => resolve(res.data),
|
|
||||||
fail: reject
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
// 写入临时文件
|
|
||||||
const tempFilePath = `${tempDir}/chunk_${Date.now()}_${i}.temp`;
|
|
||||||
await new Promise((resolve, reject) => {
|
|
||||||
fs.writeFile({
|
|
||||||
filePath: tempFilePath,
|
|
||||||
encoding: 'binary',
|
|
||||||
data: data,
|
|
||||||
success: () => resolve(),
|
|
||||||
fail: reject
|
|
||||||
});
|
|
||||||
});
|
|
||||||
chunks.push(tempFilePath);
|
|
||||||
}
|
}
|
||||||
catch (err) {
|
catch (err) {
|
||||||
console.error('分片读取失败:', err);
|
console.error('分片读取失败:', err);
|
||||||
// 清理已创建的临时文件
|
|
||||||
await cleanTempFiles(chunks);
|
|
||||||
throw new Exception_1.OakUploadException(`分片 ${i + 1} 读取失败: ${err}`);
|
throw new Exception_1.OakUploadException(`分片 ${i + 1} 读取失败: ${err}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,9 @@
|
||||||
import { EntityDict } from '../oak-app-domain';
|
import { EntityDict } from '../oak-app-domain';
|
||||||
import { BRC } from '..';
|
import { BRC } from '..';
|
||||||
import { Cache } from 'oak-frontend-base/es/features/cache'
|
import { Cache } from 'oak-frontend-base/es/features/cache'
|
||||||
|
import { UploadInterface } from 'oak-frontend-base/es/types/Upload';
|
||||||
|
|
||||||
export type UploadFn = (
|
export type UploadFn = UploadInterface['uploadFile']
|
||||||
file: File | string | Blob,
|
|
||||||
name: string, // 文件的part name
|
|
||||||
uploadUrl: string, // 上传的url
|
|
||||||
formData: Record<string, any>, // 上传的其它part参数
|
|
||||||
autoInform?: boolean, // 上传成功是否会自动通知server(若不会则需要前台显式通知
|
|
||||||
getPercent?: Function,
|
|
||||||
uploadId?: string,
|
|
||||||
method?: "POST" | "PUT" //默认POST
|
|
||||||
) => Promise<any>
|
|
||||||
|
|
||||||
export type UploadToAspect = (
|
export type UploadToAspect = (
|
||||||
file: File | string,
|
file: File | string,
|
||||||
|
|
|
||||||
|
|
@ -70,18 +70,20 @@ export default class ALiYun implements Cos<EntityDict> {
|
||||||
let response;
|
let response;
|
||||||
try {
|
try {
|
||||||
response = await uploadFn(
|
response = await uploadFn(
|
||||||
file,
|
|
||||||
'file',
|
|
||||||
uploadMeta.uploadHost,
|
|
||||||
{
|
{
|
||||||
key: uploadMeta.key,
|
file: file,
|
||||||
policy: uploadMeta.policy,
|
name: 'file',
|
||||||
ossAccessKeyId: uploadMeta.accessKey,
|
uploadUrl: uploadMeta.uploadHost,
|
||||||
signature: uploadMeta.signature,
|
formData: {
|
||||||
},
|
key: uploadMeta.key,
|
||||||
true,
|
policy: uploadMeta.policy,
|
||||||
getPercent,
|
ossAccessKeyId: uploadMeta.accessKey,
|
||||||
extraFile.id!,
|
signature: uploadMeta.signature,
|
||||||
|
},
|
||||||
|
autoInform: true,
|
||||||
|
getPercent,
|
||||||
|
uploadId: extraFile.id!,
|
||||||
|
}
|
||||||
);
|
);
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
// 网络错误
|
// 网络错误
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { sliceFile, cleanTempFiles } from '../files/slice';
|
import { MpFileGetter, sliceFile, cleanTempFiles } from '../files/slice';
|
||||||
import { OpSchema } from '../../oak-app-domain/ExtraFile/Schema';
|
import { OpSchema } from '../../oak-app-domain/ExtraFile/Schema';
|
||||||
import { UploadFn } from "../../types/Cos";
|
import { UploadFn } from "../../types/Cos";
|
||||||
import { EntityDict } from '../../oak-app-domain';
|
import { EntityDict } from '../../oak-app-domain';
|
||||||
|
|
@ -59,39 +59,41 @@ export async function chunkUpload(
|
||||||
}, 500);
|
}, 500);
|
||||||
|
|
||||||
// 上传单个分片的函数,带重试
|
// 上传单个分片的函数,带重试
|
||||||
const uploadPart = async (part: typeof chunkInfo.parts[0], chunk: File | Blob | string) => {
|
const uploadPart = async (part: typeof chunkInfo.parts[0], chunk: File | Blob | MpFileGetter) => {
|
||||||
let lastError;
|
let lastError;
|
||||||
for (let attempt = 0; attempt <= retryTimes; attempt++) {
|
for (let attempt = 0; attempt <= retryTimes; attempt++) {
|
||||||
try {
|
try {
|
||||||
|
let data: File | Blob | string;
|
||||||
|
if (chunk.type === 'getter') {
|
||||||
|
data = await (chunk as MpFileGetter).getFile() as string;
|
||||||
|
} else {
|
||||||
|
data = chunk as File | Blob;
|
||||||
|
}
|
||||||
|
|
||||||
const response = await uploadFn(
|
const response = await uploadFn(
|
||||||
chunk,
|
{
|
||||||
'file',
|
file: data,
|
||||||
part.uploadUrl,
|
name: 'file',
|
||||||
part.formData || {},
|
uploadUrl: part.uploadUrl,
|
||||||
true,
|
formData: part.formData || {},
|
||||||
(percent: number) => {
|
autoInform: true,
|
||||||
// 更新每个分片的进度
|
getPercent: (percent: number) => {
|
||||||
updateChunkPercent(part.partNumber, percent);
|
// 更新每个分片的进度
|
||||||
},
|
updateChunkPercent(part.partNumber, percent);
|
||||||
`${extraFile.id}:${part.partNumber}`,
|
},
|
||||||
"PUT"
|
uploadId: `${extraFile.id}:${part.partNumber}`,
|
||||||
|
method: "PUT"
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
// 验证上传是否成功
|
// 验证上传是否成功
|
||||||
let isSuccess = false;
|
let isSuccess = false;
|
||||||
if (process.env.OAK_PLATFORM === 'wechatMp') {
|
isSuccess = !!(response.status === 200 || response.status === 204);
|
||||||
if (response.errMsg === 'request:ok') {
|
|
||||||
const data = JSON.parse(response.data);
|
|
||||||
isSuccess = !!(data.status === 204 || data.status === 200);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
isSuccess = !!(response.status === 200 || response.status === 204);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isSuccess) {
|
if (isSuccess) {
|
||||||
// 标记该分片已完成
|
// // 标记该分片已完成
|
||||||
part.etag = (response as Response).headers?.get("ETag") || response.headers?.get("etag") || response.headers?.get("eTag")
|
// part.etag = (response as Response).headers?.get("ETag") || response.headers?.get("etag") || response.headers?.get("eTag")
|
||||||
assert(part.etag, `无法获取分片 ${part.partNumber} 的 ETag`);
|
// assert(part.etag, `无法获取分片 ${part.partNumber} 的 ETag`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -167,10 +169,5 @@ export async function chunkUpload(
|
||||||
// await onChunkSuccess(chunkInfo);
|
// await onChunkSuccess(chunkInfo);
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// 清理小程序环境下的临时文件
|
|
||||||
if (process.env.OAK_PLATFORM === 'wechatMp' && typeof file === 'string') {
|
|
||||||
await cleanTempFiles(chunks as string[]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -53,18 +53,20 @@ export default class CTYun implements Cos<EntityDict> {
|
||||||
let response;
|
let response;
|
||||||
try {
|
try {
|
||||||
response = await uploadFn(
|
response = await uploadFn(
|
||||||
file,
|
|
||||||
'file',
|
|
||||||
uploadMeta.uploadHost,
|
|
||||||
{
|
{
|
||||||
key: uploadMeta.key,
|
file: file,
|
||||||
Policy: uploadMeta.policy,
|
name: 'file',
|
||||||
AWSAccessKeyId: uploadMeta.accessKey,
|
uploadUrl: uploadMeta.uploadHost,
|
||||||
signature: uploadMeta.signature,
|
formData: {
|
||||||
},
|
key: uploadMeta.key,
|
||||||
true,
|
Policy: uploadMeta.policy,
|
||||||
getPercent,
|
AWSAccessKeyId: uploadMeta.accessKey,
|
||||||
extraFile.id,
|
signature: uploadMeta.signature,
|
||||||
|
},
|
||||||
|
autoInform: true,
|
||||||
|
getPercent,
|
||||||
|
uploadId: extraFile.id!,
|
||||||
|
}
|
||||||
);
|
);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
// 网络错误
|
// 网络错误
|
||||||
|
|
|
||||||
|
|
@ -53,16 +53,18 @@ export default class Qiniu implements Cos<EntityDict> {
|
||||||
let response;
|
let response;
|
||||||
try {
|
try {
|
||||||
response = await uploadFn(
|
response = await uploadFn(
|
||||||
file,
|
|
||||||
'file',
|
|
||||||
uploadMeta.uploadHost,
|
|
||||||
{
|
{
|
||||||
key: uploadMeta.key,
|
file,
|
||||||
token: uploadMeta.uploadToken,
|
name: 'file',
|
||||||
},
|
uploadUrl: uploadMeta.uploadHost,
|
||||||
true,
|
formData: {
|
||||||
getPercent,
|
key: uploadMeta.key,
|
||||||
extraFile.id!,
|
token: uploadMeta.uploadToken,
|
||||||
|
},
|
||||||
|
autoInform: true,
|
||||||
|
getPercent,
|
||||||
|
uploadId: extraFile.id!,
|
||||||
|
}
|
||||||
);
|
);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
// 网络错误
|
// 网络错误
|
||||||
|
|
|
||||||
|
|
@ -75,29 +75,24 @@ export default class S3 implements Cos<EntityDict> {
|
||||||
try {
|
try {
|
||||||
// S3 使用预签名 URL 直接上传,不需要额外的 formData
|
// S3 使用预签名 URL 直接上传,不需要额外的 formData
|
||||||
response = await uploadFn(
|
response = await uploadFn(
|
||||||
file,
|
{
|
||||||
'file',
|
file,
|
||||||
uploadMeta.uploadUrl,
|
name: 'file',
|
||||||
{},
|
uploadUrl: uploadMeta.uploadUrl,
|
||||||
true,
|
formData: {},
|
||||||
getPercent,
|
autoInform: true,
|
||||||
extraFile.id,
|
getPercent,
|
||||||
"PUT"
|
uploadId: extraFile.id,
|
||||||
|
method: "PUT",
|
||||||
|
isFilePath: true,
|
||||||
|
}
|
||||||
);
|
);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
throw new OakNetworkException('网络异常,请求失败');
|
throw new OakNetworkException('网络异常,请求失败');
|
||||||
}
|
}
|
||||||
|
|
||||||
let isSuccess = false;
|
let isSuccess = false;
|
||||||
if (process.env.OAK_PLATFORM === 'wechatMp') {
|
isSuccess = response.status === 200 || response.status === 204;
|
||||||
// 小程序端上传
|
|
||||||
if (response.errMsg === 'uploadFile:ok') {
|
|
||||||
const statusCode = response.statusCode;
|
|
||||||
isSuccess = statusCode === 200 || statusCode === 204;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
isSuccess = response.status === 200 || response.status === 204;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isSuccess) {
|
if (isSuccess) {
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
|
|
@ -51,25 +51,27 @@ export default class TencentYun implements Cos<EntityDict> {
|
||||||
|
|
||||||
const { extraFile, uploadFn, file, uploadToAspect, getPercent } = options;
|
const { extraFile, uploadFn, file, uploadToAspect, getPercent } = options;
|
||||||
const uploadMeta = extraFile.uploadMeta! as TencentYunUploadInfo;
|
const uploadMeta = extraFile.uploadMeta! as TencentYunUploadInfo;
|
||||||
assert(extraFile.enableChunkedUpload !== true, '暂不支持分片上传');
|
assert(extraFile.enableChunkedUpload !== true, '暂不支持分片上传');
|
||||||
let response;
|
let response;
|
||||||
try {
|
try {
|
||||||
response = await uploadFn(
|
response = await uploadFn(
|
||||||
file,
|
|
||||||
'file',
|
|
||||||
uploadMeta.uploadHost,
|
|
||||||
{
|
{
|
||||||
key: uploadMeta.key,
|
file,
|
||||||
policy: uploadMeta.policy,
|
name: 'file',
|
||||||
signature: uploadMeta.signature,
|
uploadUrl: uploadMeta.uploadHost,
|
||||||
'q-sign-algorithm': uploadMeta.algorithm,
|
formData: {
|
||||||
'q-ak': uploadMeta.accessKey,
|
key: uploadMeta.key,
|
||||||
'q-key-time': uploadMeta.keyTime,
|
policy: uploadMeta.policy,
|
||||||
'q-signature': uploadMeta.signature,
|
signature: uploadMeta.signature,
|
||||||
},
|
'q-sign-algorithm': uploadMeta.algorithm,
|
||||||
true,
|
'q-ak': uploadMeta.accessKey,
|
||||||
getPercent,
|
'q-key-time': uploadMeta.keyTime,
|
||||||
extraFile.id!
|
'q-signature': uploadMeta.signature,
|
||||||
|
},
|
||||||
|
autoInform: true,
|
||||||
|
getPercent,
|
||||||
|
uploadId: extraFile.id!
|
||||||
|
}
|
||||||
);
|
);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
// 网络错误
|
// 网络错误
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,14 @@
|
||||||
import assert from "assert";
|
import assert from "assert";
|
||||||
import { OakUploadException } from '../../types/Exception';
|
import { OakUploadException } from '../../types/Exception';
|
||||||
|
|
||||||
|
// 小程序专用类型,避免下方writeFile报错
|
||||||
|
export type MpFileGetter = {
|
||||||
|
type: 'getter',
|
||||||
|
getFile: () => Promise<string | ArrayBuffer>
|
||||||
|
};
|
||||||
|
|
||||||
// 辅助方法:将文件切片
|
// 辅助方法:将文件切片
|
||||||
export async function sliceFile(file: string | File, chunkSize: number, partCount: number): Promise<(File | Blob | string)[]> {
|
export async function sliceFile(file: string | File, chunkSize: number, partCount: number): Promise<(File | Blob | MpFileGetter)[]> {
|
||||||
if (process.env.OAK_PLATFORM === 'wechatMp') {
|
if (process.env.OAK_PLATFORM === 'wechatMp') {
|
||||||
// 微信小程序环境下,file 可能是临时文件路径字符串
|
// 微信小程序环境下,file 可能是临时文件路径字符串
|
||||||
if (typeof file === 'string') {
|
if (typeof file === 'string') {
|
||||||
|
|
@ -23,7 +29,7 @@ export async function sliceFile(file: string | File, chunkSize: number, partCoun
|
||||||
}
|
}
|
||||||
|
|
||||||
// 小程序环境下的文件分片
|
// 小程序环境下的文件分片
|
||||||
export async function sliceFileForMp(filePath: string, chunkSize: number, partCount: number): Promise<string[]> {
|
export async function sliceFileForMp(filePath: string, chunkSize: number, partCount: number): Promise<MpFileGetter[]> {
|
||||||
const fs = wx.getFileSystemManager();
|
const fs = wx.getFileSystemManager();
|
||||||
const tempDir = `${wx.env.USER_DATA_PATH}/oak_upload_temp`;
|
const tempDir = `${wx.env.USER_DATA_PATH}/oak_upload_temp`;
|
||||||
|
|
||||||
|
|
@ -36,7 +42,7 @@ export async function sliceFileForMp(filePath: string, chunkSize: number, partCo
|
||||||
fs.mkdirSync(tempDir, false);
|
fs.mkdirSync(tempDir, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
const chunks: string[] = [];
|
const chunks: MpFileGetter[] = [];
|
||||||
|
|
||||||
// 读取文件信息
|
// 读取文件信息
|
||||||
const fileStat = fs.statSync(filePath);
|
const fileStat = fs.statSync(filePath);
|
||||||
|
|
@ -49,35 +55,16 @@ export async function sliceFileForMp(filePath: string, chunkSize: number, partCo
|
||||||
const length = Math.min(chunkSize, fileSize - start);
|
const length = Math.min(chunkSize, fileSize - start);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 读取分片数据
|
chunks.push({
|
||||||
const data = await new Promise<string>((resolve, reject) => {
|
type: 'getter',
|
||||||
fs.readFile({
|
getFile: async () => {
|
||||||
filePath: filePath,
|
// 读取分片数据
|
||||||
encoding: 'binary',
|
const data = fs.readFileSync(filePath, 'binary', start, length);
|
||||||
position: start,
|
return data;
|
||||||
length: length,
|
}
|
||||||
success: (res) => resolve(res.data as string),
|
|
||||||
fail: reject
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// 写入临时文件
|
|
||||||
const tempFilePath = `${tempDir}/chunk_${Date.now()}_${i}.temp`;
|
|
||||||
await new Promise<void>((resolve, reject) => {
|
|
||||||
fs.writeFile({
|
|
||||||
filePath: tempFilePath,
|
|
||||||
encoding: 'binary',
|
|
||||||
data: data,
|
|
||||||
success: () => resolve(),
|
|
||||||
fail: reject
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
chunks.push(tempFilePath);
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('分片读取失败:', err);
|
console.error('分片读取失败:', err);
|
||||||
// 清理已创建的临时文件
|
|
||||||
await cleanTempFiles(chunks);
|
|
||||||
throw new OakUploadException(`分片 ${i + 1} 读取失败: ${err}`);
|
throw new OakUploadException(`分片 ${i + 1} 读取失败: ${err}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue