Merge remote-tracking branch 'origin/master'
This commit is contained in:
@@ -52,6 +52,17 @@ export const createFileTask = data =>
|
||||
request({ url: `${fileTaskBaseUrl}/createFileTask`, method: 'post', data });
|
||||
export const getPartUploadUrl = (id, partNumber) =>
|
||||
request({ url: `${fileTaskBaseUrl}/getUploadUrl`, method: 'get', params: { id, partNumber } });
|
||||
export const uploadPartByProxy = (id, partNumber, partBlob) => {
|
||||
const formData = new FormData();
|
||||
formData.append('file', partBlob, `part-${partNumber}.bin`);
|
||||
return request({
|
||||
url: `${fileTaskBaseUrl}/uploadPart`,
|
||||
method: 'post',
|
||||
params: { id, partNumber },
|
||||
data: formData,
|
||||
timeout: 600000,
|
||||
});
|
||||
};
|
||||
export const updateFileTask = data =>
|
||||
request({ url: `${fileTaskBaseUrl}/updateFileTask`, method: 'post', data });
|
||||
export const pauseFileTask = ids =>
|
||||
|
||||
@@ -96,11 +96,25 @@ const uploadReplaceFile = async file => {
|
||||
if (!task?.id || !task.objectKey) throw new Error('创建分片上传任务失败');
|
||||
replaceProgress.value = 0;
|
||||
for (let partNumber = 1; partNumber <= task.chunkTotal; partNumber += 1) {
|
||||
const urlRes = await api.getPartUploadUrl(task.id, partNumber);
|
||||
const part = file.slice((partNumber - 1) * chunkSize, Math.min(partNumber * chunkSize, file.size));
|
||||
const response = await fetch(urlRes.data?.data, { method: 'PUT', body: part });
|
||||
if (!response.ok) throw new Error(`分片${partNumber}上传失败`);
|
||||
const etag = String(response.headers.get('etag') || '').replaceAll('"', '');
|
||||
const urlRes = await api.getPartUploadUrl(task.id, partNumber);
|
||||
const url = urlRes.data?.data;
|
||||
let etag = '';
|
||||
const needProxy =
|
||||
typeof window !== 'undefined' &&
|
||||
window.location.protocol === 'https:' &&
|
||||
String(url || '')
|
||||
.trim()
|
||||
.toLowerCase()
|
||||
.startsWith('http:');
|
||||
if (!url || needProxy) {
|
||||
const proxyRes = await api.uploadPartByProxy(task.id, partNumber, part);
|
||||
etag = String(proxyRes.data?.data || '').replaceAll('"', '');
|
||||
} else {
|
||||
const response = await fetch(url, { method: 'PUT', body: part });
|
||||
if (!response.ok) throw new Error(`分片${partNumber}上传失败`);
|
||||
etag = String(response.headers.get('etag') || '').replaceAll('"', '');
|
||||
}
|
||||
if (!etag) throw new Error('未获取到分片 ETag');
|
||||
await api.updateFileTask({ id: task.id, partNumber, etag });
|
||||
replaceProgress.value = Math.round((partNumber / task.chunkTotal) * 100);
|
||||
|
||||
@@ -837,6 +837,30 @@ const calculateMd5 = async file => {
|
||||
const buffer = await file.arrayBuffer();
|
||||
return md5.base64(buffer);
|
||||
};
|
||||
const needsUploadProxy = url =>
|
||||
typeof window !== 'undefined' &&
|
||||
window.location.protocol === 'https:' &&
|
||||
String(url || '')
|
||||
.trim()
|
||||
.toLowerCase()
|
||||
.startsWith('http:');
|
||||
const uploadPartWithFallback = async (taskId, partNumber, part, signal) => {
|
||||
const urlRes = await api.getPartUploadUrl(taskId, partNumber);
|
||||
if (signal?.aborted) throw new DOMException('上传已暂停', 'AbortError');
|
||||
const url = urlRes.data?.data;
|
||||
// HTTPS 页面直连 http://IP MinIO 会被 Mixed Content 拦截,回退服务端代传
|
||||
if (!url || needsUploadProxy(url)) {
|
||||
const proxyRes = await api.uploadPartByProxy(taskId, partNumber, part);
|
||||
return String(proxyRes.data?.data || '').replaceAll('"', '');
|
||||
}
|
||||
const response = await fetch(url, {
|
||||
method: 'PUT',
|
||||
body: part,
|
||||
signal,
|
||||
});
|
||||
if (!response.ok) throw new Error(`分片${partNumber}上传失败`);
|
||||
return String(response.headers.get('etag') || '').replaceAll('"', '');
|
||||
};
|
||||
const uploadParts = async (file, task, sessionId) => {
|
||||
uploading.value = true;
|
||||
activeUploadTaskId.value = task.id;
|
||||
@@ -851,21 +875,13 @@ const uploadParts = async (file, task, sessionId) => {
|
||||
) {
|
||||
ensureUploadSession(sessionId, task.id);
|
||||
if (abortController.signal.aborted) throw new DOMException('上传已暂停', 'AbortError');
|
||||
const urlRes = await api.getPartUploadUrl(task.id, partNumber);
|
||||
ensureUploadSession(sessionId, task.id);
|
||||
if (abortController.signal.aborted) throw new DOMException('上传已暂停', 'AbortError');
|
||||
const url = urlRes.data?.data;
|
||||
const part = file.slice(
|
||||
(partNumber - 1) * chunkSize,
|
||||
Math.min(partNumber * chunkSize, file.size)
|
||||
);
|
||||
const response = await fetch(url, {
|
||||
method: 'PUT',
|
||||
body: part,
|
||||
signal: abortController.signal,
|
||||
});
|
||||
if (!response.ok) throw new Error(`分片${partNumber}上传失败`);
|
||||
const etag = String(response.headers.get('etag') || '').replaceAll('"', '');
|
||||
const etag = await uploadPartWithFallback(task.id, partNumber, part, abortController.signal);
|
||||
if (!etag) throw new Error('MinIO 未返回分片 ETag,请确认跨域配置已暴露 ETag 响应头');
|
||||
await api.updateFileTask({ id: task.id, partNumber, etag });
|
||||
ensureUploadSession(sessionId, task.id);
|
||||
|
||||
Reference in New Issue
Block a user