【问题标题】:Unable to send the multi part form data from React to Express Js correctly无法将多部分表单数据从 React 正确发送到 Express Js
【发布时间】: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 将附加旧值。

标签: javascript reactjs express axios form-data


【解决方案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'} 在浏览器网络选项卡中是单个文件的文件(二进制)。感谢您的检查,但一旦它工作,我肯定会接受。当我从邮递员测试时,后端已经在工作,我认为后端没有任何问题
  • 添加了我的网络标签的屏幕截图。这是预期的,还是在快递方面遗漏了什么?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-10-28
  • 2018-03-04
  • 2020-04-11
  • 2018-08-10
  • 1970-01-01
  • 1970-01-01
  • 2018-01-04
相关资源
最近更新 更多