本文最后更新于 2024-02-22,文章内容可能已经过时。

一、图片上传问题的总结

这个问题纠结了我整整一天的时间,啊,终于在我的疯狂阅读官方文档和博客下,找到了解决办法,现在将整个图片上传至服务器的方法记录如下:

1、流程思路

客户端将图片上传至服务器,服务器会返回给你一个图片的访问路径,这时图片已经存储在了服务端,我们可以通过这个地址去访问它。而我们要处理的问题就是如何将文件对象传递给服务端,并接收到服务端返回给我们的访问地址。

2、使用到的技术

2.1、 前端我使用的是 vue 和 element-ui 中的upload上传容器。代码如下:

 <!-- 图片上传 -->
<el-form-item label="首图上传">
      <el-upload
         action="/node/adminUser/imgUpload"
         list-type="picture-card"
         :on-success="handleAvatarSuccess"
         :show-file-list="false"
         :before-upload="beforeAvatarUpload"
         name="img"           
         :headers="headers" 
       >
       //如果上传成功,后端会传来一个路径,将这个路径动态绑定,便可以显示你上传的图片
      <img v-if="imageUrl" :src="imageUrl" class="avatar" />;
      <i v-else class="el-icon-plus avatar-uploader-icon"></i>
      </el-upload>
</el-form-item>
  • 参数解释
  1. action 是你访问的后端接口,根据你自己的需求规定。

  2. list-type 图片上传容器的样式。(自己可以详读读 element-ui 中的相关文档,配置相应的参数)

  3. on-success 是上传图片成功后绑定的一个函数。函数如下:

 handleAvatarSuccess(res) {
      //res这个参数自己打印出来一看便知,在此不做解释     
      console.log(res);
     //将后端发送的地址赋值到我们需要显示的img中的src动态绑定的参数中
      this.imageUrl = res.data.path;
	 //将图片地址绑定到我们的form表单数据中 后期存入数据库中     
      this.ruleform.dialogImageUrl = res.data.path;
    },
  1. show-file-list 是是否显示已上传文件列表。

  2. before-upload 是上传图片前的一个校验函数,用于判断图片的格式大小是否符合规格。函数如下:(这里大家可以根据自己的需求来限制图片上传的规格)

beforeAvatarUpload(file) {
      const isJPG = file.type === "image/jpeg";
      const isPNG = file.type === "image/png";
      const isLt3M = file.size / 1024 / 1024 / 1024 < 3;
      if (!isJPG && !isPNG) {
        this.$message.error("上传头像图片只能是 JPG 格式或 png 格式!");
      }
      if (!isLt3M) {
        this.$message.error("上传头像图片大小不能超过 3MB!");
      }
      return isJPG && isLt3M;
    },
  1. name 这个参数特别关键,官方文档解释说它是上传的文件字段名 。这个参数是我们后端接收图片时要用的一个参数,用于辨识你的图片信息。个人理解是这个容器上传的底层可能用到了 FormData 这个对象的缘故,所以会用到name这个字段。

  2. headers 是上传的请求头,必须要设置,不然后端无法接收到对应的文件对象参数。

headers:{ enctype: "multipart/form-data"},//这里我写在了vue组件里边的data中,动态绑定了。

至此,前端的所有配置已完毕。接下来重要的部分来了,后端接收前端的传输的图片,发送给前端访问地址。

2.2 、后端我使用的是 node.js 来接收并处理图片文件信息。

  • 在服务端我用到了 express 用来创建服务,使用 multer 插件处理上传文件,他的效率是非常高的,官方文档地址(https://www.npmjs.com/package/multer)
  1. 安装 multer

    npm install --save multer  //默认生产环境安装
    
  2. 创建服务,并引入你的路由接口

    const express = require("express");
    const app = express();
    const cors = require("cors")
    // 解决跨域问题
    app.use(cors({ origin: "http://localhost:8080" }))
    // 配置静态
    app.use(express.static("./public"))
    // 解析post请求数据
    app.use(express.urlencoded({ extended: true }))
    app.use(express.json())
    
    // 链接数据库
    require("./module/mongoose/mongoose")
    //引入session
    app.use(require("./module/plugin_vue/session"))
    
    //后端路由配置的接口
    app.use("/adminUser", require("./router/amdinUser"))
    
    
    app.listen("80", () => {
        console.log("80端口启动成功");
    })
    
  3. amdinUser 文件中的子路由

const express = require("express");
const router = express.Router();
// 引入multer
const multer = require("multer")

// 上传图片的方法
const storage = multer.diskStorage({
    // 存储位置 
    destination: function (req, file, callback) {
        // 参数解释 param1:错误信息  param2:上传图片的服务端保存路径,注意这里的路径写法
        callback(null, "./public/vue_img/blogImg")
    },
    // 确定文件名,在这儿采用了时间戳和图片文件原名为上传的图片文件命名,可以保证名字不重复
    filename: function (req, file, cb) {
        cb(null, `${Date.now()}-${file.originalname}`)
    }
})
// 得到multer对象
const upload = multer({ storage: storage })
//路由接口
router.post("/imgUpload", upload.array("img", 1), (req, res) => {
    // 返回图片的地址 
    let file = req.files;
    console.log(file[0]); 
    //====此时,图片已经保存至我们的服务端了====
    let fileInfo = {}
    // 获取文件基本信息,封装好发送给前端
    fileInfo.type = file[0].mimetype;
    fileInfo.name = file[0].originalname;
    fileInfo.size = file[0].size;
    fileInfo.path = '/node/vue_img/blogImg/' + file[0].filename;
    res.send({
        code: 0, 
        value: "图片上传成功",
        data: fileInfo
    })
})

module.exports = router;

说明

  1. 这里的 upload.array("img",1) 中的 img 就是 el-upload 容器中的 name (上传文件的头部信息)名称,1代表的是上传的文件个数。如果是单个文件,官方文档说明中也可以使用 upload.single("img"),但是我试了好几次没成功,el-upload也设置了只能上传单个文件也无法生效,建议使用upload.array()。
  2. 在路由接口中使用 req.files 获取前端发送的文件对象信息,最后封装我们要返回给前端的图片访问地址。

3、效果展示

  • 前端界面成功请求服务端的图片并显示
    1645941493056-2.png

  • 服务端已经在相应目录下增加了此图片。
    1645941606618-08638.png