最近想给项目加个头像上传功能,不想要老是保存在本地。 为了方便看代码,写了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>

效果如下,这一步没什么问题

使用axios将前端的list传给后端_使用axios将前端的list传给后端

选择好图片之后,文件会传送到后端(通过接口)

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>

效果:

使用axios将前端的list传给后端_上传_02

这里用到了动态路由匹配机制,具体可以自查

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)会打印什么出来呢?

请看:

使用axios将前端的list传给后端_上传_03

文件的字段名fieldname用于标记用,指明是什么文件(可以自定义),对应前端代码部分是这里:

使用axios将前端的list传给后端_微信_04

到了服务器这边文件名并不是原先的名字originalname,名字被改成filename保存且没有后缀,所以为了保证原来的样子我们一会还要做其他处理——改名

怎么指定文件存放位置呢?

const upload = multer({
    dest:"myUpload/"//上传文件存放路径
});

没有的该文件的话会自己建立一个在根目录文件,如下

使用axios将前端的list传给后端_node.js_05

名字是经过处理后保存的,使用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