流可能是在内存中缓冲的,这就是您观察到内存使用率增加的原因.
在原始代码中,您有downloadContent
函数,该函数以流的形式获取数据并返回.但是,当您调用uploadContent
函数时,您将把流直接传递到Axios post
方法.
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.
另外,你可以拿到transform request data before it is sent to the server美元.同样,完整的请求被缓冲在内存中.
为了避免在内存中缓冲整个文件,您可以使用流作为管道在下载文件时上载文件.这样,您实质上就是在传递数据,而不是保留它.这可以通过使用流上可用的pipe
方法来实现.
const axios = require("axios");
const stream = require("stream");
async function downloadContent(downloadUrl) {
return axios
.get(downloadUrl, { responseType: "stream" })
.then((response) => response.data);
}
async function uploadContent(uploadUrl, downloadStream) {
return new Promise((resolve, reject) => {
downloadStream.pipe(
new stream.PassThrough().on("error", reject).pipe(
axios
.post(uploadUrl, downloadStream, {
headers: {
"Content-Type": "specific-content-type",
},
})
.then(resolve)
.catch(reject)
)
);
});
}
(async () => {
try {
const downloadStream = await downloadContent("download/url");
await uploadContent("upload/url", downloadStream);
console.log("Upload successful.");
} catch (error) {
console.error("An error occurred:", error);
}
})();
现在,downloadContent
函数直接返回从axios获得的流.
在uploadContent
函数中,流通过PassThrough
流直接输送到axios POST请求.这意味着,当数据被下载时,它就被上传,而不是在内存中缓冲.
现在,uploadContent
函数返回一个promise ,该promise 在上传完成时进行解析,或者在出现错误时拒绝.
最后一个调用被包装在try-Catch块中,以处理下载或上载过程中可能发生的任何错误.
这应该有助于在使用Axios的两台服务器之间传输大文件时最大限度地减少内存占用.
关键是使用pipe
method on the stream和PassThrough
stream来处理块中的数据,而不是一次缓冲所有数据.
async function uploadContent(uploadUrl, downloadStream) {
return new Promise((resolve, reject) => {
downloadStream.pipe(
new stream.PassThrough().on("error", reject).pipe(
axios
.post(uploadUrl, downloadStream, {
headers: {
"Content-Type": "specific-content-type",
},
})
.then(resolve)
.catch(reject)
)
);
});
}
pipe
方法是Node.js Streams的一个特性,它允许您将streamlink 在一起.当您将一个流转换为另一个流时,数据将以小块的形式从源流流入目标流.这样,您就不必在内存中缓冲文件的全部内容.PassThrough
流是一个简单的流,它除了将数据从源传递到目标之外什么也不做.在这里使用它是为了方便配管过程.
通过使用pipe
,您实际上是在告诉程序在下载数据时以块的形式传递数据.这样,Axios将能够以块的形式发送数据,而不是等待整个流在内存中进行缓冲.
请注意,更新后的代码可能无法在浏览器环境中运行,因为它依赖于Node.js流特性.它适用于服务器端Node.js环境,在该环境中您可以更好地控制流和网络请求.这种方法利用Node.js流来最大限度地减少传输大文件时的内存使用.