前后端结合busboy插件实现完整的上传图片功能

上传图片流程:前端配置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>

猜你喜欢

转载自blog.csdn.net/minusing/article/details/137809467