使用axios上传文件到cloudinary文件服务并获取上传进度

问题描述 投票:0回答:1

我有一个 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?

reactjs axios fetch cloudinary
1个回答
0
投票

要将上传进度从

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 期间的进度。祝你好运。

© www.soinside.com 2019 - 2024. All rights reserved.