坑 前端采用post请求,在ctx.body中接收不到前端传回来的数据。 解决方案1 使用multiparty插件,在form.parse中可以接受到前端用form表单传回来的参数以及文件。 遇到的问题如下: 使用multiparty接受到的文件,但是文件为file格式,并且经过编码,这又是一大坑,目前还没解决,如果有解决办法欢迎各位大神留言。 解决方案二 使用egg自带方法ctx.getFileStream获取前端传回来的数据,当part.length存在时处理前端传来的form参数,当part.length 不存在时,说明是文件,处理前端传回来的文件。 坑 遇到的问题如下: 由于解决方案一不可用,木办法,只能采用方案二,但是还有坑啊~!使用egg自带方法收到的part为filestream,node中的流有Writable,Readable,Duplex,Transform四种,如果把filestream append到form-date中,后端那边会接受不到参数。 个人思路是先转换为buffer,这里使用stream-to-array插件,完了用fs.createReadStream去读取buffer,但是使用过后发现报错。上网查后发现那个方法的本质是调用open()方法。原文所以又采用stream.PassThrough()方法将buffer转换为流,但是转换出来的流的格式为througStream,还不是我想要的流。头大,同样,这个问题也没解决,所以就留给各位大神了。 最终方案: 使用方案二接受前端文件,使用pipe管道将filestream写到本地,之后使用fs.createreadstream方法去读取本地文件,通过axios发送请求,success。 主要代码如下:
while ((part = await parts()) != null) {
if (part.length) {
// 接受前端传来的字段,代码有些生硬... 尴尬 =,= ...
switch (part[0]) {
case 'token' : token = part[1]; break;
...
}
} else {
if (!part.filename) {
return;
}
const tempPath = path.resolve(`./app/public/resource${Math.random()}${part.filename}`);
// 使用管道将filestream写入本地
part.pipe(fs.createWriteStream(tempPath));
// 使用promise 判断文件写入完成。
const fsEnd = async part => {
return new Promise(resolve => {
part.on('end', function() {
resolve();
});
});
};
await fsEnd(part);
// 由于node并没有form数据格式,所以要用form-data插件。
form.append('file', fs.createReadStream(tempPath));
form.append('module', filePath);
let result;
result = await axios.post('http://**********', form, {
headers: form.getHeaders(),
});
// 上传完毕之后,删除本地文件。
fs.unlink(tempPath, () => {
console.log('文件删除成功');
});
}
}
注:由于目前服务并没有上线,所以不确定会有什么问题,如果出现问题我会及时留言~
如果文件不是特别大的话 可以尝试让前端传base64过来 然后接受到base64转成buffer
@Helovebai 已成功上线,目前未发现问题。
@soeyi 如果用buffer的话,用fs.createreadstream去读会报错,没法传给后端
@Helovebai 前端用fileReader 就可以获取到base64 后端只要把base64 转成buffer 就好了 不需要createReadStream
@Helovebai
https://github.com/eggjs/egg/issues/3201#issuecomment-490438035
可以看看,这个是不是能解决你的问题?
原因:
ctx.getFileStream() 只能处理通过表单上传的文件(流), 而转发过来的 ReadStream
是没有 Content-Type
之类键名,所以 ctx.getFileStream() 调用到的 multipart() 方法检查到 Content-Type
值非 Content-Type must be multipart/*
就会抛出异常。
解决方案: https://github.com/waitingsong/upload-demo
- 直接发送数据流,而非采用 FormData 构造表单文件域
- 表单域(文件名) 通过请求 header 来传送
- 在 saveFile 接口中直接读取数据流,而非使用 ctx.getFileStream() 来处理
不清楚 request
模块如何发送原始数据流,所以代码用的自己的轮子。可自行尝试 request