在实际的项目中,图片的处理往往是最麻烦的,无论是前后台,我自己也试手了一两个图片上传的小项目,把步骤写下来,以后自己忘记可以返回来看一下,同时希望能够帮到小伙伴们…
前端网页
框架: vue + iview等组件来实现图片的file功能 + koa2
运用iview的Upload组件
upload组件方法方式就不过多一一赘述了,在这里提几点关键点
<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多次尝试就可以了
koa后台node框架
node后台处理图片,查了网上资料,采用了formidable的包来处理图片的,express采用formidable的npm包,而koa2采用了koa-formidable的npm包,两者没多大区别,koa-formidable只不过是formidable的再度封装和运载koa2的框架上而已
我们先看浏览器查看http的请求
图片的http请求为什么跟别的不一样,就是不一样,我们不一样,哈哈!别钻牛角,适应就行了
- 1.引入koa-formidable
-
2.
下载地址,API
- let form = formidable.parse(request);
- 图片重命名fs,放入public文件中
- 图片路径放回给前端
步骤并不复杂,只是本人对于node的模块不太熟悉,比如fs path模块,希望以后多多做node小项目,熟悉起来…
代码如下:
// 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());
复制代码
要点
1.设置静态文件 app.use(serve(__dirname))
根据个人喜好设置静态路径
默认的设置方法:
app.use(serve(__dirname) + '/public')
resolve(config[env].host + '/upload/' + avatarName)
也可以这样设置,
app.use(serve(__dirname) + '/public/upload')
resolve(config[env].host + '/' + avatarName)
复制代码
2.fs.exists新建文件,用于存放图片
新建一个匿名函数来回调判断有无该文件,有则存入,无则新建文件
let mkdirs = (dirname, callback)=> {
fs.exists(dirname, function(exists) {
if (exists) {
callback();
} else {
mkdirs(path.dirname(dirname), function() {
fs.mkdir(dirname, callback);
});
}
});
};
复制代码
3.koa框架存在异步,所以必须用await来终结异步操作
至于async/await可以去百度一下
function formImage(){
return new Promise((resolve)=> {
// 处理图片
resolve(url)
})
}
let url = await formImage();
复制代码
4.formidable处理图片,获取图片
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}
}
复制代码
完美解决跨平台的图书上传问题
项目中还有不如,如:前端上传图片的压缩问题,涉及多张上传问题,都没有实践,以后继续更新不足
这是我试水node的小项目的案例,请多指教
项目github地址:
github.com/Jaction/blo…