Axios在服务器之间传输数据流

r55awzrz  于 2023-06-29  发布在  iOS
关注(0)|答案(1)|浏览(215)

我有两个基于Axios的函数-downloadContentuploadContent
downloadContent函数以流的形式返回数据,uploadContent函数使用流上传数据。
这个想法本质上是在两个后端之间传输数据。但由于一些文件可能有点大(5- 10 GB+),我不想下载文件在内存中,然后上传它。
但这正是我在下面的方法/代码中观察到的--进程内存使用量不断增加,直到达到文件大小(ish)。

async function downloadContent(downloadUrl) {
  return await axios
    .get(downloadUrl, {
      responseType: "stream",
    })
    .then((r) => ({
      file: r.data,
      someOtherProps: {},
    }));
}

async function uploadContent() {
  const download = await downloadContent("download/url");

  return await axios.post("upload/url", download.file, {
    headers: {
      "Content-Type": "specific-content-type",
    },
  });
}

await uploadContent();

是我做错了什么吗?
一般来说,我如何在两台服务器之间实现流式传输,以最大限度地减少Axios的内存占用?

ztigrdn8

ztigrdn81#

流可能正在内存中缓冲,这就是您观察到内存使用量增加的原因。
在原始代码中,有downloadContent函数,它以流的形式获取数据并返回。但是,当您调用uploadContent函数时,您将流直接传递到Axios post方法中。

return await axios.post("upload/url", download.file, {
    headers: {
      "Content-Type": "specific-content-type",
    },
});

默认情况下,Axios库在发出HTTP请求之前缓冲整个输入。当您将流作为数据参数(download.file)直接传递给axios.post方法时,Axios会等待整个流被消耗(在内存中缓冲),然后才真正发出HTTP请求。
这是因为Axios设计用于浏览器和Node.js,以及浏览器环境streams cannot be sent as request data directly
因此,Axios在内存中缓冲流,以确保跨环境的兼容性。这就是导致大文件占用大量内存的原因。
另外,您可以在将请求数据发送到服务器之前对其进行转换。同样,完整请求被缓冲在存储器中。
若要避免在内存中缓冲整个文件,可以将流用作管道,以便在下载文件时上载文件。这样,您实际上是在传递数据,而不是保留它。
由于Axios不支持用作可写流,因此不能使用pipe方法将数据直接导入axios.post
相反,您应该将可读流作为数据参数传递给axios.post,这与您最初所做的类似,但要确保流得到正确处理。

const axios = require('axios');

async function downloadContent(downloadUrl) {
  const response = await axios.get(downloadUrl, { responseType: 'stream' });
  return response.data;
}

async function uploadContent(uploadUrl, downloadStream) {
  try {
    await axios.post(uploadUrl, downloadStream, {
      headers: {
        'Content-Type': 'specific-content-type',
      },
      maxContentLength: Infinity,
      maxBodyLength: Infinity
    });
    console.log('Upload successful.');
  } catch (error) {
    console.error('An error occurred:', error);
  }
}

(async () => {
  const downloadStream = await downloadContent('download/url');
  await uploadContent('upload/url', downloadStream);
})();

此代码将内容作为流下载,然后将其作为流上传。关键是我们将可读流作为数据参数传递给axios.post。这应该在Node.js环境中工作。

相关问题