在實際的項目中,圖片的處理每每是最麻煩的,不管是先後臺,我本身也試手了一兩個圖片上傳的小項目,把步驟寫下來,之後本身忘記能夠返回來看一下,同時但願可以幫到小夥伴們...前端
運用iview的Upload組件vue
Upload 上傳node
upload組件方法方式就不過多一一贅述了,在這裏提幾點關鍵點git
<Upload
:on-format-error="handleFormatError"
:before-upload="handleBeforeUpload"
:data='uploadData' // 傳參
multiple
action="//localhost:6001/blog/admin/edit/image" // http請求路徑
></Upload>
data() {
return {
uploadData: {
url: '', // 圖片二進制的data的url
articleId: '' // 這個詳情的ID 後臺與他綁在一塊兒
}
}
}
// 利用瀏覽器的FileReader的特性壓縮並上傳圖片
handleBeforeUpload() {
let reader = new FileReader();
reader.readAsDataURL(file);
reader.onloadend = (e)=> {
file.url = reader.result;
this.uploadData.articleId = this.$route.query.id;
this.uploadData.url = file.url;
}
}
複製代碼
前端總結: 運用iview組件來構造file上傳圖片自己不難,官方瞭解api屢次嘗試就能夠了github
node後臺處理圖片,查了網上資料,採用了formidable的包來處理圖片的,express採用formidable的npm包,而koa2採用了koa-formidable的npm包,二者沒多大區別,koa-formidable只不過是formidable的再度封裝和運載koa2的框架上而已express
圖片的http請求爲何跟別的不同,就是不同,咱們不同,哈哈!別鑽牛角,適應就好了npm
步驟並不複雜,只是本人對於node的模塊不太熟悉,好比fs path模塊,但願之後多多作node小項目,熟悉起來...api
代碼以下:瀏覽器
// app.js
const Router = require('koa-router');
const router = new Router();
const serve = require("koa-static");
const formidable = require('koa-formidable'); // 圖片處理
const fs = require('fs'); // 圖片路徑
const path = require('path'); // 圖片路徑
app.use(serve(__dirname)) // 設置靜態文件
// 新建文件,能夠去百度fs模塊
let mkdirs = (dirname, callback)=> {
fs.exists(dirname, function(exists) {
if (exists) {
callback();
} else {
mkdirs(path.dirname(dirname), function() {
fs.mkdir(dirname, callback);
});
}
});
};
router.post('/upload/image', function (ctx, next) {
let form = formidable.parse(request);
function formImage() {
return new Promise((resolve, reject) => {
form((opt, {fields, files})=> {
let url = fields.url;
let articleId = fields.articleId;
let filename = files.file.name;
console.log(files.file.path);
let uploadDir = 'public/upload/';
let avatarName = Date.now() + '_' + filename;
mkdirs('public/upload', function() {
fs.renameSync(files.file.path, uploadDir + avatarName); //重命名
resolve(config[env].host + '/' + uploadDir + avatarName)
// http://localhost:6001/public/upload/1513523744257_WX20171205-150757.png
})
})
})
}
let url = await formImage();
return {flag: '1',msg:'',data: url} // 路徑返回給前端
});
app
.use(router.routes())
.use(router.allowedMethods());
複製代碼
根據我的喜愛設置靜態路徑
默認的設置方法:
app.use(serve(__dirname) + '/public')
resolve(config[env].host + '/upload/' + avatarName)
也能夠這樣設置,
app.use(serve(__dirname) + '/public/upload')
resolve(config[env].host + '/' + avatarName)
複製代碼
新建一個匿名函數來回調判斷有無該文件,有則存入,無則新建文件bash
let mkdirs = (dirname, callback)=> {
fs.exists(dirname, function(exists) {
if (exists) {
callback();
} else {
mkdirs(path.dirname(dirname), function() {
fs.mkdir(dirname, callback);
});
}
});
};
複製代碼
至於async/await能夠去百度一下
function formImage(){
return new Promise((resolve)=> {
// 處理圖片
resolve(url)
})
}
let url = await formImage();
複製代碼
let form = formidable.parse(request);
form((opt, obj)=> {
// 代碼如上
})
// 由於obj是個對象並有fields, files兩個參數,那我直接這樣處理:
form((opt, {fields, files})=> {
// 代碼如上
// 上面的代碼最重要的就是下面這一句
// fs.renameSync(opt1,opt2) opt1 form處理的圖片路徑而不是fileds.url二進制的路徑, opt2則是重命名的圖片名稱
fs.renameSync(files.file.path, uploadDir + avatarName);
})
作完就能夠 ctx.body = {data: url, msg: '', flag: '1'} 返回給前端
複製代碼
以上是在mac筆記本操做,沒有發現錯誤,但在window系統下卻發現圖片上傳不成功,一個致命的錯誤
fs.js:439
return binding.rename(pathModule._makeLong(oldPath),
^
Error: EXDEV, cross-device link not permitted 'C:\Users\CLi\AppData\Local\Temp\df99513a93a1cbfbc26e076f8ae08b92'
at Object.fs.renameSync (fs.js:439:18)
複製代碼
查詢了報錯的緣由:是跨分區重命名文件,會有權限問題
網友解決方法之一:Node.js中所用的fs.renameSync出錯:Error: EXDEV, cross-device link not permitted
用了以上文章的解決方法: 也報錯了 util.pump is not undefined
,這下懵逼了
用了node的pipe
流方法
let readStream = fs.createReadStream(files.file.path)
let writeStream = fs.createWriteStream(uploadDir + avatarName);
readStream.pipe(writeStream);
複製代碼
代碼以下:
exports.editImages = async(ctx, next)=> {
let form = formidable.parse(ctx.request);
form.encoding = 'utf-8';
form.keepExtensions = true; //保留後綴
mkdirs('public/upload');
let imgPlay = new Promise((resolve, reject) => {
form((opt, {fields, files})=> {
let articleId = fields.articleId;
let filename = files.file.name;
let avatarName = Date.now() + '_' + filename;
let readStream = fs.createReadStream(files.file.path)
let writeStream = fs.createWriteStream(uploadDir + avatarName);
readStream.pipe(writeStream);
// fs.rename(files.file.path, uploadDir + avatarName); //window報錯了重命名
resolve({
url: config[env].host + '/' + uploadDir + avatarName
})
// http://localhost:6001/public/upload/1513523744257_WX20171205-150757.png
})
});
let imageData = await imgPlay;
ctx.body = {flag: '1' ,msg:'',data: imageData}
}
複製代碼
完美解決跨平臺的圖書上傳問題
項目中還有不如,如:前端上傳圖片的壓縮問題,涉及多張上傳問題,都沒有實踐,之後繼續更新不足
項目github地址:github.com/Jaction/blo…