You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在NuxtJS中通过multipart/form-data传输带分辨率的图片至后端?

解决NuxtJS中上传图片时同步传输分辨率的问题

问题根源

  1. 异步回调导致提交时机过早:img.onload是异步执行的,原代码在drop事件触发后立刻调用submitFiles(),此时FormData还没来得及添加任何文件,后端自然收到空数组。
  2. File对象自定义属性无法通过FormData传输:直接给File对象添加width/height属性,这些属性不会随文件一起被FormData打包传输到后端,后端无法读取到这些自定义字段。

可行解决方案

通过Promise封装图片分辨率的获取逻辑,等所有图片的分辨率都获取完成后,再将文件和对应的分辨率一起添加到FormData并提交。同时将分辨率作为独立字段与文件对应传递,方便后端接收。

修改后的完整代码

data() {
  return {
    files: [],
    formData: null,
    uploadPercentage: 0
  }
},

mounted() {
  this.formData = new FormData()
  this.$refs.fileform.addEventListener('drop', this.handleDrop.bind(this))
},

methods: {
  handleDrop(e) {
    e.preventDefault() // 阻止浏览器默认打开文件的行为
    this.files = Array.from(e.dataTransfer.files)
    this.processAndSubmitFiles()
  },

  // 封装获取图片分辨率的Promise方法
  getImageDimensions(file) {
    return new Promise((resolve) => {
      const img = new Image()
      img.onload = function() {
        resolve({
          file: file,
          width: this.width,
          height: this.height
        })
      }
      img.src = URL.createObjectURL(file)
    })
  },

  async processAndSubmitFiles() {
    try {
      // 等待所有图片的分辨率获取完成
      const filesWithDimensions = await Promise.all(
        this.files.map(file => this.getImageDimensions(file))
      )

      // 将文件和对应分辨率添加到FormData
      filesWithDimensions.forEach((item, index) => {
        this.formData.append(`files[${index}]`, item.file)
        this.formData.append(`files[${index}][width]`, item.width)
        this.formData.append(`files[${index}][height]`, item.height)
        // 也可改用数组形式:this.formData.append('widths[]', item.width),后端按数组接收
      })

      // 所有数据准备完毕后提交
      await this.submitFiles()
    } catch (err) {
      console.error('处理图片分辨率失败:', err)
    }
  },

  async submitFiles() {
    try {
      const response = await this.$axios.post('/api/upload-files', this.formData, {
        headers: { 'Content-Type': 'multipart/form-data' },
        onUploadProgress: (progressEvent) => {
          this.uploadPercentage = parseInt(
            Math.round((progressEvent.loaded / progressEvent.total) * 100)
          )
        },
      })

      const result = response.data
      if (result.success && this.uploadPercentage === 100) {
        this.$nuxt.refresh()
        this.$emit('exit', true)
      }
    } catch (err) {
      console.error('上传失败:', err)
    } finally {
      // 重置数据,避免重复上传
      this.formData = new FormData()
      this.files = []
    }
  },
}

关键修改说明

  • 用Promise.all等待异步操作完成:确保所有图片的分辨率都获取后再处理FormData,彻底解决提交时机过早的问题。
  • 独立字段传递分辨率:通过files[${index}][width]的命名方式,让后端可以按文件索引对应接收分辨率;也可改用数组字段简化接收逻辑。
  • 优化事件逻辑:移除原watch监听,改为主动触发提交,逻辑更直观;添加e.preventDefault()避免浏览器自动打开拖入的文件。

后端接收示例(Node.js/Express)

如果采用files[${index}][width]的命名方式,后端可通过req.body获取分辨率,req.files获取文件:

app.post('/api/upload-files', (req, res) => {
  const files = req.files
  // 按索引获取对应分辨率
  const firstFileWidth = req.body['files[0][width]']
  const firstFileHeight = req.body['files[0][height]']
  // 后续可遍历处理所有文件及分辨率并存入数据库
  // ...
})

内容的提问来源于stack exchange,提问作者Philippe

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 08:24:20