node实现图片上传功能
方式一
以流的形式上传图片直接返回路径,这样写:
好处:方便处理存取数据返回路径
不好的地方:可能冗余,上传的文件后面并未使用
1.用koa-body中间件
注:如果已经使用了koa-bodyParser中间件,请remove此中间件,koa-body可以代替koa-bodyParser
在app.js中使用该中间件
const koaBody = require('koa-body')
app.use(koaBody({
multipart: true
}));
注:由于图片上传文本类型为:multipart/form-data,所以需加上此条件
2.前端代码调用
注:我用的vue+antd vue写的前端,其余框架同理
3.后端node实现
(1).在/controllers/upload.js中写入
var upload_img = async (ctx, next) => {
// 上传单个文件
console.log(ctx.request.files.uploadImg, '==========================')
const file = ctx.request.files.uploadImg // 获取上传文件
// 创建可读流
const reader = fs.createReadStream(file.path);
let name=stringRandom(16, { numbers: true })+'.png';
let filePath = path.join(__dirname, '../public/upload/') + name;
// 创建可写流
const upStream = fs.createWriteStream(filePath);
// 可读流通过管道写入可写流
reader.pipe(upStream);
return ctx.body = {
code:200,
data:{
path:`/upload/${name}`,
name:file.name
},
message:"上传成功!"
} ;
};
(2)在app.js中写入:
const path = require('path');
const static = require('koa-static');//配置静态资源
//设置静态资源路径
app.use(static(
path.join(__dirname, 'public'),{ //静态文件所在目录
maxage: 30*24*60*60*1000 //指定静态资源在浏览器中的缓存时间
}
));
注:(1)ctx.request.files.uploadImg,由于前端的upload组件name为uploadImg,所以这里写uploadImg
(2)写入静态资源读取,便于前端访问该图片
(3)该方法的本质:获取图片上传者图片在他电脑位置,把这张图片通过管道存入我们指定的自己的服务器上
方式二
为了不造成服务器图片冗余,减少无需图片上传,实现:
1.前端每次上传生成base64图片(可预览)
2.当整个表单提交之后再把这个图片的base64提交给后台
3.后台接受base64图片,通过buffer转为图片格式,用stringRandom生成随机数为图片名字存储到服务器。
1.前端每次上传生成base64图片
前端代码:
<template>
<div>
<h4>上传base64图片</h4>
<input type="file" @change="Preview($event)" accept="image/*" ref="showinput">
<div>图片名字:{{imgName}}</div>
<img :src="imgData" alt="">
<a-button type="primary" @click="handleSubmit">上传</a-button>
</div>
</template>
<script>
import {SubmitBaseImg} from '../assets/js/getData'
export default {
data (){
return {
imgName:'',
imgData:'',
};
},
methods:{
Preview(ev){
// const self=this;
const file=ev.target.files[0];
this.imgName=file.name;
console.log('图片文件',ev.target.files);
this.imgObj=ev.target.files[0];
let obj=new FileReader();
obj.readAsDataURL(file);
// obj.onload=function(){
// self.img=obj.result;
// }
obj.onload=()=>{
this.picReduce(obj.result,base64=>{
this.imgData=base64
});
};
},
// 图片压缩
picReduce(picObj,callback){
let img = new Image();
img.src=picObj;
img.onload=()=>{
const w=img.width;
const h=img.height;
const scale = w/h;
const max_w=w>1080?1080:w;
const max_h=h*max_w/w;
let canvas=document.createElement("canvas");
let ctx = canvas.getContext('2d');
canvas.width=max_w;
canvas.height=max_h;
ctx.drawImage(img,0,0,max_w,max_h);
var base64 = canvas.toDataURL('image/jpeg', 0.7);
callback(base64)
}
},
handleSubmit(){
SubmitBaseImg({imgData:this.imgData,imgName:this.imgName}).then(msg=>{
if(msg.code==200){
}
})
},
},
mounted(){},
}
</script>
<style lang='less' scoped>
</style>
2.后台接受base64图片,通过buffer转为图片格式,用stringRandom生成随机数为图片名字存储到服务器
const stringRandom = require('string-random');
var upload_baseImg = async (ctx, next) => {
let {imgData,imgName}=ctx.request.body;
//过滤data:URL
var base64Data = imgData.replace(/^data:image\/\w+;base64,/, "");
var dataBuffer = Buffer.from(base64Data, 'base64');
let name=stringRandom(16, { numbers: true })+'.png';
console.log('图',name);
// let name='图.png';
let filePath = path.join(__dirname, '../public/upload/') + `${name}`;
return new Promise((res,rej)=>{
fs.writeFile(filePath, dataBuffer, function(err) {
console.log(111,err);
if(err){
res({...errorResObj})
}else{
res({
...responseObj,
data:{
path:`/upload/${name}`,
name:imgName
},
})
}
});
}).then(msg=>{
ctx.response.body=msg;
})
}