图片上传功能的实现和问题总结
本文最后更新于 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>
- 参数解释
-
action 是你访问的后端接口,根据你自己的需求规定。
-
list-type 图片上传容器的样式。(自己可以详读读 element-ui 中的相关文档,配置相应的参数)
-
on-success 是上传图片成功后绑定的一个函数。函数如下:
handleAvatarSuccess(res) {
//res这个参数自己打印出来一看便知,在此不做解释
console.log(res);
//将后端发送的地址赋值到我们需要显示的img中的src动态绑定的参数中
this.imageUrl = res.data.path;
//将图片地址绑定到我们的form表单数据中 后期存入数据库中
this.ruleform.dialogImageUrl = res.data.path;
},
-
show-file-list 是是否显示已上传文件列表。
-
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;
},
-
name 这个参数特别关键,官方文档解释说它是上传的文件字段名 。这个参数是我们后端接收图片时要用的一个参数,用于辨识你的图片信息。个人理解是这个容器上传的底层可能用到了 FormData 这个对象的缘故,所以会用到name这个字段。
-
headers 是上传的请求头,必须要设置,不然后端无法接收到对应的文件对象参数。
headers:{ enctype: "multipart/form-data"},//这里我写在了vue组件里边的data中,动态绑定了。
至此,前端的所有配置已完毕。接下来重要的部分来了,后端接收前端的传输的图片,发送给前端访问地址。
2.2 、后端我使用的是 node.js 来接收并处理图片文件信息。
- 在服务端我用到了 express 用来创建服务,使用 multer 插件处理上传文件,他的效率是非常高的,官方文档地址(https://www.npmjs.com/package/multer)
-
安装 multer
npm install --save multer //默认生产环境安装
-
创建服务,并引入你的路由接口
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端口启动成功"); })
-
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;
说明:
- 这里的 upload.array("img",1) 中的 img 就是 el-upload 容器中的 name (上传文件的头部信息)名称,1代表的是上传的文件个数。如果是单个文件,官方文档说明中也可以使用 upload.single("img"),但是我试了好几次没成功,el-upload也设置了只能上传单个文件也无法生效,建议使用upload.array()。
- 在路由接口中使用 req.files 获取前端发送的文件对象信息,最后封装我们要返回给前端的图片访问地址。
3、效果展示
-
前端界面成功请求服务端的图片并显示
-
服务端已经在相应目录下增加了此图片。
- 感谢你赐予我前进的力量