最近想给项目加个头像上传功能,不想要老是保存在本地。 为了方便看代码,写了demo演示一下如何上传到取回来图片,最后成果不是项目本身 前端解决方法有很多,具体说一下后端的处理
因为仅做记录,希望观者有一定的Vue和Express基础
前提是解决了跨域问题
1.前端代码
1.1上传头像
前端代码没多少好讲,重点在于跨域解决 对文件的一些判断(大小、类型)尽可能在前端完成 为了方便是使用element-ui的el-upload文件上传组件 属性用法参考官方档案:上传组件
<template>
<el-upload
name="head" //文件的名字字段,这个留着心眼
class="avatar-uploader"
action="/api2/users/touxiang" //后端接口地址(处理过)
:show-file-list="false"
:on-success="handleAvatarSuccess"
:before-upload="beforeAvatarUpload">
<img v-if="imageUrl" :src="imageUrl" class="avatar">
<i v-else class="el-icon-plus avatar-uploader-icon"></i>
</el-upload>
</template>
<script>
export default {
data() {
return {
imageUrl: ''
};
},
methods: {
handleAvatarSuccess(res, file) {
this.imageUrl = URL.createObjectURL(file.raw);
},
beforeAvatarUpload(file) {
const isJPG = file.type === 'image/jpeg';
const isLt2M = file.size / 1024 / 1024 < 2;
if (!isJPG) {
this.$message.error('上传头像图片只能是 JPG 格式!');
}
if (!isLt2M) {
this.$message.error('上传头像图片大小不能超过 2MB!');
}
return isJPG && isLt2M;
}
}
}
</script>
<style>
.avatar-uploader .el-upload {
border: 1px dashed #d9d9d9;
border-radius: 6px;
cursor: pointer;
position: relative;
overflow: hidden;
}
.avatar-uploader .el-upload:hover {
border-color: #409EFF;
}
.avatar-uploader-icon {
font-size: 28px;
color: #8c939d;
width: 178px;
height: 178px;
line-height: 178px;
text-align: center;
}
.avatar {
width: 178px;
height: 178px;
display: block;
}
</style>
效果如下,这一步没什么问题
选择好图片之后,文件会传送到后端(通过接口)
1.2调用头像
<template>
<div class="demo-basic--circle">头像框
<div class="block"><el-avatar :size="50" :src="circleUrl+'/'+picture"></el-avatar></div>
</div>
</template>
<script>
export default {
data () {
return {
picture:"微信图片_20200127233702", //这里是用户指定的标识图像的名字,改名字就可以动态改头像
circleUrl: "/api2/users/download"
}
},
}
</script>
效果:
这里用到了动态路由匹配机制,具体可以自查
src="circleUrl+'/'+picture"
实际上就是
src="/api2/users/download/微信图片_20200127233702"
我们的参数是微信图片_20200127233702
2.后端
2.1 接收图片
后端才是这次重点 之前我们前后端传来传去的都是json数据或者字符串,这次丢给后端一个文件(图片文件),那要怎么接收呢?
Express默认并不处理HTTP请求体中的数据,对于普通请求体(JSON、二进制、字符串)数据,可以使用body-parser中间件。而文件上传(multipart/form-data请求),可以基于请求流处理,也可以使用formidable模块或Multer中间件。
Multer在解析完请求体后,会向Request对象中添加一个body对象和一个file或files对象(上传多个文件时使用files对象 )。其中,body对象中包含所提交表单中的文本字段(如果有),而file(或files)对象中包含通过表单上传的文件。
上传头像是单文件处理,可以使用res.file获得文件
console.log(req.file)会打印什么出来呢?
请看:
文件的字段名fieldname用于标记用,指明是什么文件(可以自定义),对应前端代码部分是这里:
到了服务器这边文件名并不是原先的名字originalname,名字被改成filename保存且没有后缀,所以为了保证原来的样子我们一会还要做其他处理——改名
怎么指定文件存放位置呢?
const upload = multer({
dest:"myUpload/"//上传文件存放路径
});
没有的该文件的话会自己建立一个在根目录文件,如下
名字是经过处理后保存的,使用fs模块对系统文件及目录进行读写操作
改名操作:
fs.renameSync('myUpload/' + file.filename, 'myUpload/' + file.originalname);//这里修改文件名字
源代码:
const express = require('express');
const router = express.Router();
const user = require('../model/user');
const multer = require('multer');
let fs = require("fs");
const upload = multer({
dest:"myUpload/"//上传文件存放路径
});
const singleMidle = upload.single("head");//一次处理一张head字段名的文件,字段名一定要对应!
//接收过来的头像文件
router.post('/touxiang', singleMidle, function(req, res, next) {
console.log(req.file);
let file = req.file;
//文件改名保存
fs.renameSync('myUpload/' + file.filename, 'myUpload/' + file.originalname);//这里修改文件名字
res.send("服务器结束工作");
});
//获得用户头像src
router.get('/download/:picture',function (req,res) {
console.log(req.params.picture);
res.sendFile(process.cwd()+"/myUpload/"+req.params.picture+".jpg")
});
=================后面的代码略
2.2 前端调用后端图片
//获得用户头像src
router.get('/download/:picture',function (req,res) {
console.log(req.params.picture);
res.sendFile(process.cwd()+"/myUpload/"+req.params.picture+".jpg")//服务器该文件的绝对路径
});
已知前端图片的
src="/api2/users/download/微信图片_20200127233702"
动态路由匹配机制将:picture匹配微信图片_20200127233702 然后使用req.params.picture获得我们之前提到的参数微信图片_20200127233702