最近在写的后台涉及到了banner图的管理,于是我又研究了egg的文件上传,本来想用它的file模式,但是除了很多莫名其妙的bug,项目又很赶,只能先用stream模式,于是途中又去研究了node的流,现在头很大。
明明只是写一个简单的后台而已,为什么这么难搞,我太难了。😢
1.安装两个依赖,await-stream-ready 和 stream-wormhole
await-stream-ready:顾名思义,能够使用await进行文件的读写操作。
stream-wormhole:在文件上传出现异常时能够把流消耗掉。
不安装也没事,但是最好是安装了吧。
npm i await-stream-ready -S
npm i stream-wormhole -S
2.在要使用的controller文件中引入
const awaitWriteStream = require('await-stream-ready').write;
const sendToWormhole = require('stream-wormhole');
3.获取流
const stream = await ctx.getFileStream();
4.生成文件名
这里我直接用了上传文件的文件名,有需要的可以自己定义
const filename = stream.filename;
5.生成文件路径
同样可以自己定义放在哪个文件夹,但是要是在public下面的子文件夹
const target = path.join('app/public/uploads', filename);
6.生成文件写入文件流
const writeStream = fs.createWriteStream(target);
7.异步写入文件流
try {
await awaitWriteStream(stream.pipe(writeStream));
} catch (err) {
await sendToWormhole(stream);
throw err;
}
8.到第7步就是文件上传的所有代码了,这样文件上传基本就没有问题了,但是由于需要前端提交img地址到数据库进行关联,因此这里需要返回上传成功的图片的服务器端访问地址给前端。
egg框架静态资源默认都是放在public下面的,访问地址为ip:端口/public/…
// 返回网络访问地址
const imageUrl = path.join('/public/uploads', filename);
// 文件响应
ctx.body = {
code: 200,
data: {
msg: '上传成功',
imgUrl: imageUrl,
},
// url: '/public/uploads/' + filename,
};
这样子,前端接收到该字段之后就可以通过ip:端口+返回的img地址访问到该图片了。
Vue代码如下:
在main.js中绑定文件地址前缀为全局变量
Vue.prototype.$fileUrl = 'http://127.0.0.1:7001'
在模板中使用
<img v-if="user.avater" :src="$fileUrl+user.avater" alt="">
<img v-else src="../assets/user_img.jpg" alt="">
这块代码仍需要很多优化,如:生成随机图片名,防止名字冲突。根据图片id找到之前的图片将其删除。以达到banner图的覆盖等等,虽然感觉不会很难,但是最近项目很赶,看心情吧😀。