这段时间没啥事,自己研究了一下express上传图片的操作,这样就摆脱了后台语言使用java的局限,也能对上传的整体流程有更深的理解.当然在继续往下看的前提是大家对express要有简单的认识.最快的方法是看MDN中的图书管理DEMO,这个网址打开需要靠人品:有时候架"梯子"也不好使.
在开始码代码之前我们得先开通阿里云并且需要OSS对象存储,准备好这些我们就开始吧.
前端上传页面,我使用的是art-template模板,当然也可以使用pug,html或其他模板.
views/avatar.art
<form action="./upload_mult" method="post" enctype="multipart/form-data">
<input type="file" name="avatar" id="avatar" multiple />
<button class="btn" id="btn" type="submit">提交</button>
</form>
先看一下使用表单提交的方式上传单张图片,这里需要注意一点form中的属性设置,特别是不要忘记指定enctype="multipart/form-data"
接着我们写服务器代码,下面的代码用作与OSS进行交互的配置
controllers/uploadController.js
let co = require('co'); // 这里[co](https://www.npmjs.com/package/co)处理nodejs阻塞问题
let fs = require('fs');
let OSS = require('ali-oss');
let uuidv4 = require('uuid/v4');
let client = new OSS({
region: '<Your region>',
accessKeyId: '<Your AccessKeyId>', //OSS控制台,鼠标移到头像时获取
accessKeySecret: '<Your AccessKeySecret>'
});
var ali_oss = {
bucket: 'self-upload'
}
分离的routes/catalog.js
//图片上传引用的npm包
var multer = require('multer'); // 查文档
var upload = multer({ dest: 'upload/' });
// 单图上传
router.post('/upload', upload.single('avatar'), upload_controller.upload_post);
//多图上传
router.post('/upload_mult', upload.array('avatar', 3), upload_controller.upload_post);
//混合上传 (不同字段限制数量不同)
var cpUpload = upload.fields([{ name: 'avatar', maxCount: 1 }, { name: 'gallery', maxCount: 3 }])
router.post('/cool-profile', cpUpload, upload_controller.upload_post)
上传的时候首先将图片上传到我们的服务器,然后重命名再传至OSS,最后将我们服务器中的图片删除
controllers/uploadController.js
exports.upload_post = function(req, res, next) {
if(req.file) {
// 文件路径
var filePath = './' + req.file.path;
// 文件类型
var temp = req.file.originalname.split('.');
var fileType = temp[temp.length - 1];
var lastName = '.' + fileType;
// 构建图片名
var fileName = Date.now() + lastName;
// 图片重命名
fs.rename(filePath, fileName, (err) => {
if (err) {
res.end(JSON.stringify({status:'102',msg:'文件写入失败'}));
}else{
var localFile = './' + fileName;
var key = fileName;
// 阿里云 上传文件
co(function* () {
client.useBucket(ali_oss.bucket);
var result = yield client.put(key, localFile);
var imageSrc = 'http://image.hgdqdev.cn/' + result.name;
// 上传之后删除本地文件
res.end(JSON.stringify({status:'100',msg:'上传成功',imageUrl:imageSrc}));
}).catch(function (err) {
// 上传之后删除本地文件
res.end(JSON.stringify({status:'101',msg:'上传失败',error:JSON.stringify(err)}));
});
fs.unlinkSync(localFile);
}
});
}
res.end();
}
上面的方法使用与传单张图片,如果是多张图片需要遍历一下,对每一张图片处理,这里将重命名和上传方法进行了拆分并封装到一个对象中
function HandleFile(fileItem) {
this.fileItem = fileItem;
this.fileName = '';
this.localFile = '';
}
/**
* res: 响应(必填)
*/
HandleFile.prototype.ossUpload = function(res) {
var self = this;
co(function* () {
client.useBucket(ali_oss.bucket);
var result = yield client.put(self.fileName, self.localFile);
var imageSrc = result.url;
res.end(JSON.stringify({ code: 12000, msg:'上传成功', imageUrl:imageSrc }));
}).catch(function (err) {
res.end(JSON.stringify({ code:13000,msg:'上传失败', error: err }));
});
self.localFile && fs.unlinkSync(self.localFile);
}
/**
* res: 响应(必填)
* next: 错误处理(必填)
* 给图片重命名后上传
*/
HandleFile.prototype.imgRename = function(res, next) {
var self = this;
var filePath = './' + this.fileItem.path;
var _temp = this.fileItem.originalname.split('.');
var _fileType = _temp[_temp.length - 1];
var _lastName = '.' + _fileType;
this.fileName = uuidv4() + _lastName;
this.localFile = './' + this.fileName;
fs.rename(filePath, self.fileName, (err) => {
if(err) {
res.end(JSON.stringify({code:13000,msg:'文件上传失败!'}));
}
self.ossUpload(res);
})
}
exports.upload_post = function(req, res, next) {
if(req.file) {
new HandleFile(req.file).imgRename(res, next);
} else if(req.files) {
var files = req.files;
files.forEach(function(item) {
new HandleFile(item).imgRename(res, next);
})
}
res.end(); //为了防止上传出错页面始终处于加载状态,可以自定义处理方法
}
因为单张和多张上传req中的参数是不一样的,单张是req.file, 多张是req.files,代码中需要加一个if判断,如果是ajax再加一个判断:
前端代码修改:
<form>
<input type="file" name="avatar" id="avatar" />
<input type="hidden" id="base64" >
<button class="btn" id="btn" type="button">提交</button>
</form>
<script>
$('#avatar').change(function() {
var files = this.files;
var reader = new FileReader();
reader.onload = function(event) {
// console.log(event.target.result);
$('#base64').val(event.target.result);
}
reader.readAsDataURL(files[0]);
})
$('#btn').click(function() {
$.ajax({
url: 'upload_mult',
type: 'POST',
data: { avatar: $('#base64').val() },
success: function(res) {
console.log(res);
},
error: function(err) {
console.log(err);
}
})
})
</script>
服务端代码添加:
else if(req.body && req.body.avatar) { // ajax方式提交base64
var avatar = req.body.avatar;
var fileName = uuidv4() + '.png';
var filePath = './upload/' + fileName;
var base64Data = avatar.replace(/^data:image\/\w+;base64,/, "");
var dataBuffer = new Buffer(base64Data, 'base64');
fs.writeFile(filePath, dataBuffer, function(err) {
if(err) {
res.end(JSON.stringify({code:13000,msg:'文件上传失败!'}));
} else {
var handle = new HandleFile();
handle.fileName = fileName;
handle.localFile = filePath;
handle.ossUpload(res);
}
})
}
文章参考 https://blog.csdn.net/zhuming3834/article/details/77531127?locationNum=6&fps=1
DEMO地址: https://github.com/baobz/node-shop