Node.js 将两个侦听器连接到单个axios流

Node.js 将两个侦听器连接到单个axios流,node.js,node-streams,Node.js,Node Streams,我正在尝试从axios获取pdf url作为流。我需要进一步上传该文件到另一个位置,并返回上传文件的哈希值。我有第三方的功能,接受流,并上传文件到目标位置。如何使用相同的流来获取文件的哈希? 我正在尝试运行以下代码: const getFileStream = await axios.get<ReadStream>(externalUrl, { responseType: "stream" }); const hashStream = crypto.createHash("m

我正在尝试从axios获取pdf url作为流。我需要进一步上传该文件到另一个位置,并返回上传文件的哈希值。我有第三方的功能,接受流,并上传文件到目标位置。如何使用相同的流来获取文件的哈希? 我正在尝试运行以下代码:

const getFileStream = await axios.get<ReadStream>(externalUrl, {
    responseType: "stream"
});
const hashStream = crypto.createHash("md5");
hashStream.setEncoding("hex");
const pHash = new Promise<string>(resolve => {
    getFileStream.data.on("finish", () => {
      resolve(hashStream.read());
 });
});

const pUploadedFile = externalUploader({
  stream: () => getFileStream.data
});

getFileStream.data.pipe(hashStream);

const [hash, uploadedFile] = await Promise.all([pHash, pUploadedFile]);

return { hash, id: uploadedFile.id };
const getFileStream=wait axios.get(externalUrl{
响应类型:“流”
});
const hashStream=crypto.createHash(“md5”);
hashStream.setEncoding(“十六进制”);
const pHash=新承诺(解决=>{
getFileStream.data.on(“finish”,()=>{
解析(hashStream.read());
});
});
const pUploadedFile=externalUploader({
流:()=>getFileStream.data
});
getFileStream.data.pipe(hashStream);
const[hash,uploadedFile]=wait Promise.all([pHash,puploaddedfile]);
返回{hash,id:uploadedFile.id};

运行此代码后,当我下载相同的pdf文件时,我得到了损坏的文件

您可以重用相同的axios
getFileStream.data
以通过管道传输到多个接收器,只要它们同时被使用

下面是使用axios流下载文件并“并发”计算文件的MD5校验和,同时将其上载到远程服务器的示例

该示例将输出标准输出:

Incoming file checksum: 82c12f208ea18bbeed2d25170f3669a5
File uploaded. Awaiting server response...
File uploaded. Done.
工作示例:

const{Writable,Readable,Transform,pipeline}=require('stream');
const crypto=require('crypto');
常量https=require('https');
const axios=require('axios');
(异步()=>{
//创建axios流以获取文件
const axiosStream=等待axios.get('https://upload.wikimedia.org/wikipedia/commons/thumb/8/86/Map_icon.svg/128px-Map_icon.svg.png', {
响应类型:“流”
}); 
//要将文件重新上载到远程服务器,我们可以使用需要边界密钥的多部分/表单数据
const key=crypto.randomBytes(16).toString('hex');
//创建一个请求,将文件作为多部分/表单数据流传输到另一台服务器
const req=https.request({
主机名:“postman echo.com”,
路径:'/post',
方法:“POST”,
标题:{
“内容类型”:“多部分/表单数据;边界=-->{key}`,
“传输编码”:“分块”
}
});
//创建一个承诺,当远程服务器完成HTTP(S)请求时,该承诺将被解析/拒绝
const uploadRequestPromise=新承诺(解析=>req.once('response',(incomingMessage)=>{
incomingMessage.resume();//防止响应数据在内存中排队
incomingMessage.on('end',()=>{
if(incomingMessage.statusCode==200){
解决();
}
否则{
拒绝(新错误(`Received status code${incomingMessage.statusCode}`)
}
});
}));
//构造多部分/表单数据分隔符
const multipartPrefix=`\r\n---${key}\r\n`+
'内容处置:表单数据;filename=“cool name.png”\r\n'+
'内容类型:image/png\r\n'+
“\r\n”;
const multipartSuffix=`\r\n--${key}--`;
//在流式传输文件内容之前,写入多部分/表单数据请求的开头
请求写入(多部分前缀);
//创建一个承诺,该承诺将在文件完成上载后兑现
const uploadStreamFinishedPromise=新承诺(解析=>{
管道(
//将axios请求用作流源
axiosStream.data,
//借助于方便的flush()调用,nodejs转换流可以
//添加多部分/表单数据后缀
新变换({
objectMode:false,
转换(块、编码、下一步){
下一步(null,chunk);
},
刷新(下一个){
this.push(multipartSuffix);
next();
}
}),
//将流数据写入远程服务器
请求,
//处理完流管道中的所有数据后,将执行此回调
(错误)=>{
如果(错误){
拒绝(错误);
}
否则{
解决();
}
}
)
});
//创建MD5流哈希器
const hasher=crypto.createHash(“md5”);
//创建一个承诺,该承诺将在哈希函数处理完所有流后解析
//资料
const hashPromise=新承诺(resolve=>管道(
//将axios请求用作流源。
//请注意,可以使用同一个流将管道连接到多个接收器
//使用相同的axios流计算haas和上传上述文件
axiosStream.data,
//has函数将处理流数据
哈舍,
//处理完流管道中的所有数据后,将执行此回调
(错误)=>{
如果(错误){
拒绝(错误);
}
否则{
解决();
}
}
));
/**
*请注意,在建立两个流汇之前没有“等待”,即
*这很重要,因为我们希望两个接收器都从流的开始处理数据
*/
//我们必须等待调用哈希函数的digest(),直到处理完所有数据
等待承诺;
常量hash=hasher.digest(“十六进制”);
log(“传入文件校验和:”,哈希);
等待上传StreamFinishedPromise;
log(“文件已上载。正在等待服务器响应…”);
等待上传请求;
log(“文件上传.完成”);
})()
.catch(console.error);