• 使用axios发送post请求上传文件(multipartform-data)到后端


    项目场景:

    后端:实现了一个文件上传服务接口,可以接收前端传递过来的MultipartFile文件,并存储到服务器本地中。
    前端:获取typefile标签中的文件,使用axioshttp请求库,发送post请求,将文件发送给后端。

    问题描述

    在js中发送上传文件请求的常规代码如下:

    • new一个FormData对象,使用append方法将文件添加到表单中

      • FormData专门用于js中发送multipart/form-data格式请求
      • append方法的key为表单中的name属性,即后端需要接收的参数名

      async handleUploadFile(event) {
      const file = event.target.files[0]
      let formData = new FormData()
      formData.append(‘files’, file)
      const res = await service({
      url: ‘/api/files/upload’,
      method: ‘POST’,
      headers: {
      ‘Content-Type’: ‘multipart/form-data’
      },
      data: formData
      })
      console.log(res.data);
      }

    实际运行以上这段代码时,会发现后端报500错误如下:

    Caused by: java.io.IOException:
    org.apache.tomcat.util.http.fileupload.FileUploadException: the request was rejected because no multipart boundary was found
    
    • 1
    • 2

    大概的意思是说,后端无法识别到传递来的文件中的boundary,从而无法区分一个文件的内容从报文的哪个地方开始,又从报文的哪个地方结束,最终导致文件上传失败。


    原因分析:

    分析以上这种情况的原因,是因为我在发送请求时将请求头中Content-Type属性给写死为multipart/form-data浏览器无法自动给我们的报文添加boundary

    我尝试将前端请求config中,headers配置移除,如下:

    async handleUploadFile(event) {
      const file = event.target.files[0]
      let formData = new FormData()
      formData.append('files', file)
      const res = await service({
        url: '/api/files/upload',
        method: 'POST',
        data: formData
      })
      console.log(res.data);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    再次发送请求,这次仍然没有请求成功。服务器没有报错了,但是后端获取不到文件数据。继续分析请求报文,发现属性值变为application/x-www-form-urlencoded,这是发送普通的表单,肯定是无法正确将文件送达的。


    解决方案:

    在查阅了网上大量的帖子之后得知,axios在请求发送出去之前会进行一次拦截,自动给我们的请求设置一些参数。上面会出现application/x-www-form-urlencoded这个参数就是因为axios设置了post请求的默认请求头,如果我们没有在config中指定其它请求头的话,就会使用默认的。

    又了解到,发送multipart/form-data格式的请求时,不需要我们自己指定Content-Type属性,由浏览器自动帮我们去设置。

    那么解决问题的关键就是不让axios帮我们自动配置

    axiosconfig中有一个transformRequest属性,官方的解释是可以在请求发送之前让我们人为干预。属性值是一个数组,里面可以定义一个函数,接收两个参数,分别是dataheadersdata就是我们刚刚定义的FormData对象,headers里面则是axios预定义的请求头。

    打印headers
    headers对象中的属性
    post属性中的Content-Type属性删掉即可解决问题。

    最终代码如下:

    async handleUploadFile(event) {
      const file = event.target.files[0]
      let formData = new FormData()
      formData.append('files', file)
      const res = await service({
        url: '/api/files/upload',
        method: 'POST',
        transformRequest: [function(data, headers) {
          // 去除post请求默认的Content-Type
          delete headers.post['Content-Type']
          return data
        }],
        data: formData
      })
      console.log(res.data);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    以上的解决方法是我不断试错之后得出来的,网上关于这个问题的很多帖子都不能解决,气死我了。。。希望这篇帖子能帮助大家避免踩这个坑吧~

    先自我介绍一下,小编13年上师交大毕业,曾经在小公司待过,去过华为OPPO等大厂,18年进入阿里,直到现在。深知大多数初中级java工程师,想要升技能,往往是需要自己摸索成长或是报班学习,但对于培训机构动则近万元的学费,着实压力不小。自己不成体系的自学效率很低又漫长,而且容易碰到天花板技术停止不前。因此我收集了一份《java开发全套学习资料》送给大家,初衷也很简单,就是希望帮助到想自学又不知道该从何学起的朋友,同时减轻大家的负担。添加下方名片,即可获取全套学习资料哦

  • 相关阅读:
    快来看看Python内置函数一览表
    栈和队列的应用 —— 顺序队列
    21、Flink 的table API与DataStream API 集成(2)- 批处理模式和inser-only流处理
    Linux下Samba服务安装及启用全攻略
    Reactive的使用(reactive 和 shallowReactive使用上区别)
    SystemUI导航栏
    LintCode 163 · Unique Binary Search Trees (DP 或 Catalan数)
    使用mysql语句进行分组查询
    宝塔 php修改了php.ini配置不生效
    mysql回表查询和索引覆盖
  • 原文地址:https://blog.csdn.net/m0_54850825/article/details/126080914