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

IT技术 javascript reactjs express axios form-data
2021-05-12 23:25:14

我正在尝试使用 Dropzone 上传文件并将这些文件从 React JS 发送到 java 后端 API。这里 React 是将文档发送到表达后端并添加一些键,然后将最终的表单数据发送到后端 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

react测试.js

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

expressTest.Js module [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 module中设置内容类型,但在后端端点中获取所有空值

'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
1个回答

问题是append方法FormData采用字符串或单个文件作为值,并且“如果没有指定这些值,则将值转换为字符串”。然而,您正在传递一个文件数组( selectedFiles),它被字符串化为"[object File]"(如果一次选择两个文件,它将是[object File],[object File]- 只是做什么Array.prototype.toStringObject.prototype.toString做什么)。

你需要做

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>
  )
}

浏览器网络选项卡 在此处输入图片说明