方式一
以流的形式上傳圖片直接返回路徑,這樣寫:
好處:方便處理存取數據返回路徑
不好的地方:可能冗余,上傳的文件后面並未使用
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;
})
}