上传图片流程:前端配置contentType请求头为multipart/form-data,上传图片后,后端接收到图片通过文件库操作以及busboy库将图片以流的形式存入到后端项目的指定文件夹中,然后就可以通过后端的地址+图片路径访问上传的图片
更多busboy库的api可以查看文档:https://www.npmjs.com/package/busboy
首先安装busboy库:
npm install busboy
前后端代码:
后端-express:
const express = require('express');
const router = express.Router();
// node提供的文件操作库
const path = require('path')
const fs = require('fs')
// 引入busboy库
const busboy = require('busboy')
//上传图片接口-/uploadImg
//数据传递格式为:multipart/form-data
router.post('/uploadImg', (req, resp) => {
let pathUrl = ''
// const random = (() => {
// const buf = Buffer.alloc(4);
// //生成8位随机数
// return () => randomFillSync(buf).toString('hex');
// })();
const bb = busboy({
headers: req.headers });
bb.on('file', (name, file, info) => {
//使用时间戳作为图片前缀(确保图片名称的唯一性)
pathUrl = `/imgs/upload/${
+new Date()}-${
info.filename}`
// 图片存储路径(这里存入到了项目的public文件夹下)
const saveTo = path.join(__dirname, '../public' + pathUrl);
// 将图片流存入为指定文件夹下的图片文件
file.pipe(fs.createWriteStream(saveTo));
});
bb.on('close', () => {
resp.send({
code: 200,
msg: `图片(${
pathUrl})上传成功`,
data: {
pathUrl }
});
});
req.pipe(bb);
return;
})
//删除图片接口-/deleteUploadImg
router.get('/deleteUploadImg', (req, resp) => {
const name = req.query.name
//去除字符串前后的引号
const pathUrl = path.join(__dirname, '../public', name.replace(/^['"]+|['"]+$/g, ""))
console.log('删除的图片路径:', pathUrl);
// 删除图片
fs.unlink(pathUrl, (err) => {
if (err) {
resp.send({
code: 404,
msg: err
})
} else {
resp.send({
code: 200,
msg: `图片(${
pathUrl})删除成功`
});
}
})
})
前端-vue3+element-plus(以上传头像业务场景为例)
<template>
<!-- element提供的上传文件组件:headers配置请求头contentType,action为后端上传图片接口 -->
<el-upload :headers="{ contentType: 'multipart/form-data' }" :show-file-list="false"
:action="formData.websiteAddress + '/api/uploadImg'" :on-success="uploadImg" :on-error="uploadFail">
<!-- 头像回显 -->
<div class="avatar">
<div class="avatar-item">
<img :src="formData.websiteAddress + formData.avatar" alt="" />
</div>
</div>
</el-upload>
</template>
<script setup lang='ts'>
//表单数据,包含用户头像avatar字段(临时保存,如果点击提交就把保存的头像存入数据库和仓库)
let formData = ref<any>({
})
//上传头像成功
const uploadImg = (res: any) => {
console.log('上传文件成功:', res);
//(业务逻辑代码,可忽略)
//上传头像就删除服务器上一张头像
delAvatar()
//更新头像
if (res.code === 200) {
formData.value.avatar = res.data.pathUrl
} else {
ElMessage.error('图片上传出现错误')
}
}
//头像上传失败
const uploadFail = (err: any) => {
ElMessage.error('图片上传出现错误', err)
}
//删除头像(业务逻辑代码,可忽略)
//在请求拦截中将删除头像的请求不带上token,避免上传请求后token失效导致删除图片失败
const delAvatar = async () => {
//判断上一张头像如果是项目正在使用的,就不删除,不然就删除(临时的,不点提交就不作数)
if (formData.value.avatar != blogMes.value.avatar) {
// 调删除头像的接口
let delres = await deleteImg(formData.value.avatar)
if (delres.code === 200) {
console.log(delres.msg);
}
}
}
</script>