使用Axios将文件上传到云文件服务并获取上传进度

vx6bjr1n  于 2023-10-18  发布在  iOS
关注(0)|答案(1)|浏览(149)

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

lndjwyie

lndjwyie1#

要将上传进度从uploader.upload_stream传递到Axios uploadProgress事件,您可以创建一个自定义Readable流,该流在数据上传到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);
  });
}

在这个修改后的代码中,我向uploadWrapper函数添加了一个onProgress回调,在上传过程中调用该函数来计算进度,并通过req.respondWith方法将进度发送给Axios uploadProgress事件。
通过这种方式,您可以跟踪并将上传进度从您的API路由传递到客户端,在上传到您的API路由和随后上传到Cloudinary期间显示进度。祝你好运

相关问题