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) {
|
||||
return;
|
||||
}
|
||||
const { reqId, key } = task;
|
||||
const { reqId, key, controller } = task;
|
||||
const { loaded, i, j, files, totalSize } = fileInfo;
|
||||
|
||||
// 检查是否已取消
|
||||
if (controller.signal.aborted) {
|
||||
throw new Error("Upload cancelled");
|
||||
}
|
||||
|
||||
const formData = await buildFormData({
|
||||
file: files[i],
|
||||
i,
|
||||
@@ -110,6 +116,7 @@ export function useFileSliceUpload(
|
||||
|
||||
let newTask = { ...task };
|
||||
await uploadChunk(key, formData, {
|
||||
signal: controller.signal,
|
||||
onUploadProgress: (e) => {
|
||||
const loadedSize = loaded + e.loaded;
|
||||
const curPercent = Number((loadedSize / totalSize) * 100).toFixed(2);
|
||||
@@ -141,9 +148,10 @@ export function useFileSliceUpload(
|
||||
reqId,
|
||||
isCancel: false,
|
||||
cancelFn: () => {
|
||||
task.controller.abort();
|
||||
// 使用 newTask 的 controller 确保一致性
|
||||
newTask.controller.abort();
|
||||
cancelUpload?.(reqId);
|
||||
if (task.updateEvent) window.dispatchEvent(new Event(task.updateEvent));
|
||||
if (newTask.updateEvent) window.dispatchEvent(new Event(newTask.updateEvent));
|
||||
},
|
||||
};
|
||||
updateTaskList(newTask);
|
||||
@@ -153,8 +161,16 @@ export function useFileSliceUpload(
|
||||
|
||||
let loaded = 0;
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
// 检查是否已取消
|
||||
if (newTask.controller.signal.aborted) {
|
||||
throw new Error("Upload cancelled");
|
||||
}
|
||||
const { slices } = files[i];
|
||||
for (let j = 0; j < slices.length; j++) {
|
||||
// 检查是否已取消
|
||||
if (newTask.controller.signal.aborted) {
|
||||
throw new Error("Upload cancelled");
|
||||
}
|
||||
await uploadSlice(newTask, {
|
||||
loaded,
|
||||
i,
|
||||
@@ -219,9 +235,10 @@ export function useFileSliceUpload(
|
||||
reqId,
|
||||
isCancel: false,
|
||||
cancelFn: () => {
|
||||
task.controller.abort();
|
||||
// 使用 newTask 的 controller 确保一致性
|
||||
newTask.controller.abort();
|
||||
cancelUpload?.(reqId);
|
||||
if (task.updateEvent) window.dispatchEvent(new Event(task.updateEvent));
|
||||
if (newTask.updateEvent) window.dispatchEvent(new Event(newTask.updateEvent));
|
||||
},
|
||||
};
|
||||
updateTaskList(newTask);
|
||||
@@ -232,13 +249,26 @@ export function useFileSliceUpload(
|
||||
|
||||
// 逐个处理文件
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
// 检查是否已取消
|
||||
if (newTask.controller.signal.aborted) {
|
||||
throw new Error("Upload cancelled");
|
||||
}
|
||||
|
||||
const file = files[i];
|
||||
console.log(`[useSliceUpload] Processing file ${i + 1}/${files.length}: ${file.name}`);
|
||||
|
||||
const result = await streamSplitAndUpload(
|
||||
file,
|
||||
(formData, config) => uploadChunk(task.key, formData, config),
|
||||
(formData, config) => uploadChunk(task.key, formData, {
|
||||
...config,
|
||||
signal: newTask.controller.signal,
|
||||
}),
|
||||
(currentBytes, totalBytes, uploadedLines) => {
|
||||
// 检查是否已取消
|
||||
if (newTask.controller.signal.aborted) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 更新进度
|
||||
const overallBytes = totalProcessedBytes + currentBytes;
|
||||
const curPercent = Number((overallBytes / totalSize) * 100).toFixed(2);
|
||||
@@ -260,9 +290,9 @@ export function useFileSliceUpload(
|
||||
1024 * 1024, // 1MB chunk size
|
||||
{
|
||||
reqId,
|
||||
hasArchive: task.hasArchive,
|
||||
prefix: task.prefix,
|
||||
signal: task.controller.signal,
|
||||
hasArchive: newTask.hasArchive,
|
||||
prefix: newTask.prefix,
|
||||
signal: newTask.controller.signal,
|
||||
maxConcurrency: 3,
|
||||
}
|
||||
);
|
||||
|
||||
@@ -442,6 +442,11 @@ export async function streamSplitAndUpload(
|
||||
* 上传单行内容
|
||||
*/
|
||||
async function uploadLine(line: string, index: number): Promise<void> {
|
||||
// 检查是否已取消
|
||||
if (signal?.aborted) {
|
||||
throw new Error("Upload cancelled");
|
||||
}
|
||||
|
||||
if (!line.trim()) {
|
||||
skippedEmptyCount++;
|
||||
return;
|
||||
@@ -455,6 +460,11 @@ export async function streamSplitAndUpload(
|
||||
const slices = sliceFile(lineFile, DEFAULT_CHUNK_SIZE);
|
||||
const checkSum = await calculateSHA256(slices[0]);
|
||||
|
||||
// 检查是否已取消(计算哈希后)
|
||||
if (signal?.aborted) {
|
||||
throw new Error("Upload cancelled");
|
||||
}
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append("file", slices[0]);
|
||||
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) {
|
||||
if (event.lengthComputable) {
|
||||
|
||||
Reference in New Issue
Block a user