You've already forked DataMate
fix: 修复上传取消功能,确保 HTTP 请求正确中止
- 在 XMLHttpRequest 中添加 signal.aborted 检查 - 修复 useSliceUpload 中的 cancelFn 闭包问题 - 确保流式上传和分片上传都能正确取消
This commit is contained in:
@@ -99,8 +99,14 @@ export function useFileSliceUpload(
|
|||||||
if (!task) {
|
if (!task) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const { reqId, key } = task;
|
const { reqId, key, controller } = task;
|
||||||
const { loaded, i, j, files, totalSize } = fileInfo;
|
const { loaded, i, j, files, totalSize } = fileInfo;
|
||||||
|
|
||||||
|
// 检查是否已取消
|
||||||
|
if (controller.signal.aborted) {
|
||||||
|
throw new Error("Upload cancelled");
|
||||||
|
}
|
||||||
|
|
||||||
const formData = await buildFormData({
|
const formData = await buildFormData({
|
||||||
file: files[i],
|
file: files[i],
|
||||||
i,
|
i,
|
||||||
@@ -110,6 +116,7 @@ export function useFileSliceUpload(
|
|||||||
|
|
||||||
let newTask = { ...task };
|
let newTask = { ...task };
|
||||||
await uploadChunk(key, formData, {
|
await uploadChunk(key, formData, {
|
||||||
|
signal: controller.signal,
|
||||||
onUploadProgress: (e) => {
|
onUploadProgress: (e) => {
|
||||||
const loadedSize = loaded + e.loaded;
|
const loadedSize = loaded + e.loaded;
|
||||||
const curPercent = Number((loadedSize / totalSize) * 100).toFixed(2);
|
const curPercent = Number((loadedSize / totalSize) * 100).toFixed(2);
|
||||||
@@ -141,9 +148,10 @@ export function useFileSliceUpload(
|
|||||||
reqId,
|
reqId,
|
||||||
isCancel: false,
|
isCancel: false,
|
||||||
cancelFn: () => {
|
cancelFn: () => {
|
||||||
task.controller.abort();
|
// 使用 newTask 的 controller 确保一致性
|
||||||
|
newTask.controller.abort();
|
||||||
cancelUpload?.(reqId);
|
cancelUpload?.(reqId);
|
||||||
if (task.updateEvent) window.dispatchEvent(new Event(task.updateEvent));
|
if (newTask.updateEvent) window.dispatchEvent(new Event(newTask.updateEvent));
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
updateTaskList(newTask);
|
updateTaskList(newTask);
|
||||||
@@ -153,8 +161,16 @@ export function useFileSliceUpload(
|
|||||||
|
|
||||||
let loaded = 0;
|
let loaded = 0;
|
||||||
for (let i = 0; i < files.length; i++) {
|
for (let i = 0; i < files.length; i++) {
|
||||||
|
// 检查是否已取消
|
||||||
|
if (newTask.controller.signal.aborted) {
|
||||||
|
throw new Error("Upload cancelled");
|
||||||
|
}
|
||||||
const { slices } = files[i];
|
const { slices } = files[i];
|
||||||
for (let j = 0; j < slices.length; j++) {
|
for (let j = 0; j < slices.length; j++) {
|
||||||
|
// 检查是否已取消
|
||||||
|
if (newTask.controller.signal.aborted) {
|
||||||
|
throw new Error("Upload cancelled");
|
||||||
|
}
|
||||||
await uploadSlice(newTask, {
|
await uploadSlice(newTask, {
|
||||||
loaded,
|
loaded,
|
||||||
i,
|
i,
|
||||||
@@ -219,9 +235,10 @@ export function useFileSliceUpload(
|
|||||||
reqId,
|
reqId,
|
||||||
isCancel: false,
|
isCancel: false,
|
||||||
cancelFn: () => {
|
cancelFn: () => {
|
||||||
task.controller.abort();
|
// 使用 newTask 的 controller 确保一致性
|
||||||
|
newTask.controller.abort();
|
||||||
cancelUpload?.(reqId);
|
cancelUpload?.(reqId);
|
||||||
if (task.updateEvent) window.dispatchEvent(new Event(task.updateEvent));
|
if (newTask.updateEvent) window.dispatchEvent(new Event(newTask.updateEvent));
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
updateTaskList(newTask);
|
updateTaskList(newTask);
|
||||||
@@ -232,13 +249,26 @@ export function useFileSliceUpload(
|
|||||||
|
|
||||||
// 逐个处理文件
|
// 逐个处理文件
|
||||||
for (let i = 0; i < files.length; i++) {
|
for (let i = 0; i < files.length; i++) {
|
||||||
|
// 检查是否已取消
|
||||||
|
if (newTask.controller.signal.aborted) {
|
||||||
|
throw new Error("Upload cancelled");
|
||||||
|
}
|
||||||
|
|
||||||
const file = files[i];
|
const file = files[i];
|
||||||
console.log(`[useSliceUpload] Processing file ${i + 1}/${files.length}: ${file.name}`);
|
console.log(`[useSliceUpload] Processing file ${i + 1}/${files.length}: ${file.name}`);
|
||||||
|
|
||||||
const result = await streamSplitAndUpload(
|
const result = await streamSplitAndUpload(
|
||||||
file,
|
file,
|
||||||
(formData, config) => uploadChunk(task.key, formData, config),
|
(formData, config) => uploadChunk(task.key, formData, {
|
||||||
|
...config,
|
||||||
|
signal: newTask.controller.signal,
|
||||||
|
}),
|
||||||
(currentBytes, totalBytes, uploadedLines) => {
|
(currentBytes, totalBytes, uploadedLines) => {
|
||||||
|
// 检查是否已取消
|
||||||
|
if (newTask.controller.signal.aborted) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// 更新进度
|
// 更新进度
|
||||||
const overallBytes = totalProcessedBytes + currentBytes;
|
const overallBytes = totalProcessedBytes + currentBytes;
|
||||||
const curPercent = Number((overallBytes / totalSize) * 100).toFixed(2);
|
const curPercent = Number((overallBytes / totalSize) * 100).toFixed(2);
|
||||||
@@ -260,9 +290,9 @@ export function useFileSliceUpload(
|
|||||||
1024 * 1024, // 1MB chunk size
|
1024 * 1024, // 1MB chunk size
|
||||||
{
|
{
|
||||||
reqId,
|
reqId,
|
||||||
hasArchive: task.hasArchive,
|
hasArchive: newTask.hasArchive,
|
||||||
prefix: task.prefix,
|
prefix: newTask.prefix,
|
||||||
signal: task.controller.signal,
|
signal: newTask.controller.signal,
|
||||||
maxConcurrency: 3,
|
maxConcurrency: 3,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -442,6 +442,11 @@ export async function streamSplitAndUpload(
|
|||||||
* 上传单行内容
|
* 上传单行内容
|
||||||
*/
|
*/
|
||||||
async function uploadLine(line: string, index: number): Promise<void> {
|
async function uploadLine(line: string, index: number): Promise<void> {
|
||||||
|
// 检查是否已取消
|
||||||
|
if (signal?.aborted) {
|
||||||
|
throw new Error("Upload cancelled");
|
||||||
|
}
|
||||||
|
|
||||||
if (!line.trim()) {
|
if (!line.trim()) {
|
||||||
skippedEmptyCount++;
|
skippedEmptyCount++;
|
||||||
return;
|
return;
|
||||||
@@ -455,6 +460,11 @@ export async function streamSplitAndUpload(
|
|||||||
const slices = sliceFile(lineFile, DEFAULT_CHUNK_SIZE);
|
const slices = sliceFile(lineFile, DEFAULT_CHUNK_SIZE);
|
||||||
const checkSum = await calculateSHA256(slices[0]);
|
const checkSum = await calculateSHA256(slices[0]);
|
||||||
|
|
||||||
|
// 检查是否已取消(计算哈希后)
|
||||||
|
if (signal?.aborted) {
|
||||||
|
throw new Error("Upload cancelled");
|
||||||
|
}
|
||||||
|
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
formData.append("file", slices[0]);
|
formData.append("file", slices[0]);
|
||||||
formData.append("reqId", reqId.toString());
|
formData.append("reqId", reqId.toString());
|
||||||
|
|||||||
@@ -92,6 +92,14 @@ class Request {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 监听 AbortSignal 来中止请求
|
||||||
|
if (config.signal) {
|
||||||
|
config.signal.addEventListener("abort", () => {
|
||||||
|
xhr.abort();
|
||||||
|
reject(new Error("上传已取消"));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// 监听上传进度
|
// 监听上传进度
|
||||||
xhr.upload.addEventListener("progress", function (event) {
|
xhr.upload.addEventListener("progress", function (event) {
|
||||||
if (event.lengthComputable) {
|
if (event.lengthComputable) {
|
||||||
|
|||||||
Reference in New Issue
Block a user