我有一个 React 组件,它通过我自己的 Web API 端点使用 axios 将文件上传到 cloudinary。总体流程如下: axios 将请求发送到 localhost/api/files/upload 然后在这个端点我使用以下代码将文件发送到 cloudinary:
export async function POST(req: NextRequest) {
try {
const formData = await req.formData();
const formDataEntryValues = Array.from(formData.values());
for (const formDataEntryValue of formDataEntryValues) {
if (typeof formDataEntryValue === "object" && "arrayBuffer" in formDataEntryValue) {
const file = formDataEntryValue as unknown as Blob;
if (file.size > config.maxFileSize) {
return BadRequest(`Max file size is ${config.maxFileSizeAsString}`);
}
const buffer = Buffer.from(await file.arrayBuffer());
const response = await uploadWrapper(buffer);
return NextResponse.json(response, { status: 200 });
}
}
} catch (error: any) {
return NextResponse.json(error, { status: 500 });
}
}
const uploadWrapper = async (buffer: Buffer) => {
return new Promise(async (resolve, reject) => {
// Here I stream file with cloudinary's library
const cloud_upload_stream = await cloudinary.v2.uploader.upload_stream({
folder: config.storePath
}, (error, result) => {
if (error) {
reject(error);
} else {
resolve(result);
}
});
streamifier.createReadStream(buffer).pipe(cloud_upload_stream);
})
}
我用 axios 发送文件并接收 axios uploadProgressEvent 以将其显示在网页上。当我将文件上传到 api 路由时,我发现进度正常,在 100% 上传时,我需要等待更多时间,因为文件是通过 uploader.upload_stream 流式传输到 cloudinary 的。如何通过我的 api 将进度从 uploader.upload_stream 传递到 axios uploadProgress 事件?所以 uploadProgressEvent 显示上传到 api 路由以及从 api 路由到 cloudinary?
要将上传进度从
uploader.upload_stream
传递到 Axios uploadProgress
事件,您可以创建一个自定义可读流,该流在数据上传到 Cloudinary 时拦截数据并发出事件来更新进度。您可以通过以下方式修改代码来实现此目的:
export async function POST(req: NextRequest) {
try {
const formData = await req.formData();
const formDataEntryValues = Array.from(formData.values());
for (const formDataEntryValue of formDataEntryValues) {
if (typeof formDataEntryValue === "object" && "arrayBuffer" in formDataEntryValue) {
const file = formDataEntryValue as unknown as Blob;
if (file.size > config.maxFileSize) {
return BadRequest(`Max file size is ${config.maxFileSizeAsString}`);
}
const buffer = Buffer.from(await file.arrayBuffer());
const response = await uploadWrapper(buffer, (progress) => {
// You can pass the progress here to the Axios uploadProgress event
req.respondWith(
NextResponse.json({ progress }, { status: 200 })
);
});
return NextResponse.json(response, { status: 200 });
}
}
} catch (error: any) {
return NextResponse.json(error, { status: 500 });
}
}
const uploadWrapper = async (buffer: Buffer, onProgress: (progress: number) => void) => {
return new Promise(async (resolve, reject) => {
const cloud_upload_stream = await cloudinary.v2.uploader.upload_stream({
folder: config.storePath
}, (error, result) => {
if (error) {
reject(error);
} else {
resolve(result);
}
});
let bytesUploaded = 0;
let totalBytes = buffer.length;
streamifier.createReadStream(buffer)
.on('data', (chunk) => {
bytesUploaded += chunk.length;
const progress = (bytesUploaded / totalBytes) * 100;
// Call the progress callback to send progress to Axios
onProgress(progress);
})
.pipe(cloud_upload_stream);
});
}
在这段修改后的代码中,我向
onProgress
函数添加了 uploadWrapper
回调,该回调在上传过程中被调用,以计算进度并通过 uploadProgress
方法将进度发送到 Axios req.respondWith
事件。
通过这种方式,您可以跟踪 API 路由的上传进度并将其传递到客户端,显示上传到 API 路由以及随后上传到 Cloudinary 期间的进度。祝你好运。