无法将多部分表单数据从 React 正确发送到 Express Js

Posted

技术标签:

【中文标题】无法将多部分表单数据从 React 正确发送到 Express Js【英文标题】:Unable to send the multi part form data from React to Express Js correctly 【发布时间】:2021-05-02 14:37:27 【问题描述】:

我正在尝试使用 Dropzone 上传文件并将这些文件从 React JS 发送到 java 后端 API。这里 React 将文档发送到 express 后端并添加一些键,然后将最终的表单数据发送到后端 java 端点。但无法在后端获取文件和请求部分。快递收到的数据格式错误,感谢任何帮助。

上传我的文件.jsx

const UploadMyFiles = () => 

  const [selectedFiles, setSelectedFiles]= useState(null)
  const [userName,setUserName]=userState('TestUser')

  const handleUserFileUpload = (userSelectedFiles) => 
        setSelectedFiles(userSelectedFiles)  

    const formData = new FormData()

    formData.append('files', selectedFiles)
    formData.append('userName', userName,)
    const  res = sendDocument(formData) //refer reactTest.js module below

  

  return (

          <div className='myClass'>Select Bill</div>
          <Dropzone
            accept='.pdf'
            onDrop=selectedFiles => handleUserFileUpload (selectedFiles)
          >
            ( getRootProps, getInputProps ) => (<div ...getRootProps() id='no-padding'>
              <input
                ...getInputProps()
                type='file'
                id='attachments'
                name='attachments'
                className='myclass'
              />              
            
            </div>
            )
          </Dropzone>
  )

export default UploadMyFiles

reactTest.js

export const sendDocument = async (myFormData) => 
  return await axios(
    method: 'post',
    url: `/sendDocument`,
    data: myFormData,
    headers:  'Content-Type': 'multipart/form-data' 
  );
;

expressTest.Js 模块 [Node JS]

const express = require('express')
const axios = require('axios')
const router = express.Router()

router.post('/', (req, res) => 
  console.log(req.body) //see **output below, File data is in string format which is causing the wrong format in my axios router call to backend. How do I get actual file instead of this [object File]. I beliver it is because of multer bodyparser
  console.log(JSON.parse(req.body.myFormData.userName))
  axios(
    method: 'post',
    url: '/sendMyUserData',
    data: req.body,
    headers: 
      apiKey: 'keytoapi'
      //'Content-Type': 'multipart/form-data'
    
  )
    .then(response => 
      
      return res.send(res)
    )
    .catch(error => 
      console.error('error')
     

**console.log 的输出

"files":"[object File]","userName":"TestUser"

如您所见,“文件”数据是字符串格式,这导致我的 Axios 路由器调用后端时“数据”的 formData 格式错误。如何获取实际文件而不是此 [目标文件]?我相信这是因为 multer bodyparser。

我的后端 Java 端点

@PostMapping(path = "/sendMyUserData", consumes =  MediaType.MULTIPART_FORM_DATA_VALUE )
        public String uploadMyUserData(@RequestPart(value = "files") final MultipartFile[] multipartFiles, @RequestPart(value = "userName", required = true) String userName ) 
            return myService.storeFiles(multipartFiles, userName));
    

例外:

org.springframework.web.HttpMediaTypeNotSupportedException: Content type 'application/json;charset=utf-8' not supported

我尝试在 expressTest.js 模块中设置内容类型,但我在后端端点中获得了所有空值

'Content-Type': 'multipart/form-data;

完整的请求标头 - 从浏览器网络选项卡的请求中捕获

Request URL: http://localhost:8080/sendMyUserData
Referrer Policy: strict-origin-when-cross-origin
Accept: application/json, text/plain, */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9,te;q=0.8
Authorization:mytoken
Connection: keep-alive
Content-Length: 83474
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryvooZbILex2ARkOrs
Cookie: Host: localhost:8080
Origin: http://localhost:8080
Referer: http://localhost:8080/sendDocument
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-origin
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (Khtml, like Gecko) Chrome/88.0.4324.114 Safari/537.36
------WebKitFormBoundaryvooZbILex2ARkOrs
Content-Disposition: form-data; name="userName"

TestUser
------WebKitFormBoundaryvooZbILex2ARkOrs
Content-Disposition: form-data; name="files"; filename="Xyz.pdf"
Content-Type: application/pdf

【问题讨论】:

java 后端无关。您的 express.js 代理服务器已经收到错误的请求数据 - res.body 甚至似乎是一个 JSON 文档。请edit您的问题包括与从输入元素获取文件并使用 axios 发出请求相关的完整前端代码。 感谢@Bergi 查看它。我已经更新了帖子并包含了具有发送 formData 逻辑的代码 您使用的是哪个Dropzone 库,that one? @Bergi,这是正确的 react-dropzone 顺便说一句,setSelectedFiles(userSelectedFiles) 钩子使用错误,附加 selectedFiles 将附加旧值。 【参考方案1】:

问题在于the append method of FormData 使用字符串或单个文件作为值,并且“如果没有指定这些值,则值将转换为字符串”。但是,您正在传递一个 array 文件 (selectedFiles),它被字符串化为 "[object File]"(如果一次选择两个文件,它将是 [object File],[object File] - 正是 Array.prototype.toString 和 @ 987654331@做)。

你需要这样做

const UploadMyFiles = () => 
  const [userName,setUserName] = userState('TestUser')
  const handleUserFileUpload = (selectedFiles) => 
    const formData = new FormData()
    for (const file of selectedFiles)
      formData.append('files', file)
    formData.append('userName', userName)
    sendDocument(formData).catch(…)
  

  return (
    <div className='myClass'>Select Bill</div>
      <Dropzone
        accept='.pdf'
        onDrop=handleUserFileUpload
      >…</Dropzone>
    </div>
  )

浏览器网络选项卡

【讨论】:

我几个小时前刚做过。我尝试使用 formData.append("files[], selectedFiles[0]) 并尝试现在只发送一个文件。我仍然可以看到输出为 [Object: null prototype] folderName: 'TestUser' adding files[] ,向我显示网络 heders 选项卡中的文件名,文件作为二进制文件(二进制)发送,但不显示其他任何内容,我的后端无法读取,说多部分异常和读取超时 @mark 现在这意味着您的前端终于可以正常工作了,可以正确发送文件,而您的后端需要修复。请接受这个关于前端部分的答案,然后用新信息更新the question about the backend,我们可以在那里讨论如何正确使用 multer。 我不确定它是否正常工作,但 console.log(req.body.files) 仍然显示 [object null prototype] userName:'TestUser' 在浏览器网络选项卡中是单个文件的文件(二进制)。感谢您的检查,但一旦它工作,我肯定会接受。当我从邮递员测试时,后端已经在工作,我认为后端没有任何问题 添加了我的网络标签的屏幕截图。这是预期的,还是在快递方面遗漏了什么?

以上是关于无法将多部分表单数据从 React 正确发送到 Express Js的主要内容,如果未能解决你的问题,请参考以下文章

CORS XMLHttpRequest 使用 POST 将多部分表单数据发送到 Softlayer 对象存储失败

ajax 将多部分表单数据作为 json 对象上传

无法使用 Ajax 将多部分文件从 JSP 传递到 Spring MVC 中的控制器

无法打印从 Flask 后端发送的表单中的元素 [重复]

从浏览器获取相同的会话到 Adob​​e

验证失败后,servlet中止多部分表单数据提交