Axios在服务器之间流传数据

huangapple go评论77阅读模式
英文:

Axios stream data between servers

问题

我有两个基于 Axios 的函数 - downloadContentuploadContent

downloadContent 函数以流的形式返回数据,而 uploadContent 函数使用该流进行上传。

总体思路是在两个后端之间传输数据流。但由于一些文件可能相当大(5-10GB+),我不想将文件下载到内存中,然后再上传。

但是,使用下面的方法/代码时,我观察到的情况正是这样 - 进程的内存使用一直在不断增加,直到达到文件大小(左右)。

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 在两个服务器之间进行流传输以减小内存占用?

注意: 请确保您的 Axios 版本支持流响应和流请求。这可以通过确保 Axios 版本是 0.21.0 或更高版本来实现。

英文:

I have two Axios based functions - downloadContent and uploadContent

The downloadContent function returns the data as a stream and the uploadContent function uses the stream to upload it.

The idea is to essentially stream data between two backends. But since some of the files can be a bit large (5-10GB+) i dont want to download the file in memory and then upload it.

But thats exactly what im observing with the approach/code below - the process memory usage is going constantly up until it reaches the file size(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();

Is it something im doing wrong?

And in general how can i achieve streaming between two server to minimize the memory footprint with Axios?

答案1

得分: 1

有可能数据流被缓存在内存中,这就是为什么您观察到内存使用增加的原因。

在原始代码中,您有一个名为 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 中运行,而在浏览器环境中,无法直接发送流作为请求数据。因此,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('上传成功。');
  } catch (error) {
    console.error('发生错误:', error);
  }
}

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

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

英文:

It is possible that the stream is being buffered in memory, which is why you are observing an increase in memory usage.

In the original code, you have the downloadContent function, which gets data as a stream and returns it. However, when you call the uploadContent function, you are passing the stream directly into the Axios post method.

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

The Axios library, by default, buffers the entire input before making the HTTP request. When you pass the stream directly as the data parameter (download.file) to the axios.post method, Axios waits for the entire stream to be consumed (buffered in memory) before it actually makes the HTTP request.
This is because Axios is designed to work with both browsers and Node.js, and in a browser environment, streams cannot be sent as request data directly.
Therefore, Axios buffers the stream in memory to ensure compatibility across environments. This is what leads to high memory usage for large files.

Plus, you can transform request data before it is sent to the server. Again, the full request is buffered in memory.


To avoid buffering the entire file in memory, you can use the stream as a pipe to upload the file while it is being downloaded. This way, you are essentially passing the data through without holding onto it.

Since Axios does not support being used as a writable stream, you cannot use the pipe method to pipe data directly into axios.post.
Instead, you should pass the readable stream as the data parameter to axios.post, which is similar to what you were doing originally, but ensure that the stream is being handled properly.

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);
})();

This code downloads content as a stream and then uploads it as a stream. The key is that we are passing the readable stream as the data parameter to axios.post. This should work in a Node.js environment.

huangapple
  • 本文由 发表于 2023年6月26日 01:03:31
  • 转载请务必保留本文链接:https://go.coder-hub.com/76551552.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定