【问题标题】:React.js, how to send a multipart/form-data to serverReact.js,如何将 multipart/form-data 发送到服务器
【发布时间】:2025-12-04 08:10:01
【问题描述】:

我们想将图片文件作为multipart/form发送到后端,我们尝试使用html表单获取文件并将文件作为formData发送,这里是代码

export default class Task extends React.Component {

  uploadAction() {
    var data = new FormData();
    var imagedata = document.querySelector('input[type="file"]').files[0];
    data.append("data", imagedata);

    fetch("http://localhost:8910/taskCreationController/createStoryTask", {
      mode: 'no-cors',
      method: "POST",
      headers: {
        "Content-Type": "multipart/form-data"
        "Accept": "application/json",
        "type": "formData"
      },
      body: data
    }).then(function (res) {
      if (res.ok) {
        alert("Perfect! ");
      } else if (res.status == 401) {
        alert("Oops! ");
      }
    }, function (e) {
      alert("Error submitting form!");
    });
  }

  render() {
    return (
        <form encType="multipart/form-data" action="">
          <input type="file" name="fileName" defaultValue="fileName"></input>
          <input type="button" value="upload" onClick={this.uploadAction.bind(this)}></input>
        </form>
    )
  }
}

后端的错误是 "嵌套异常是 org.springframework.web.multipart.MultipartException: 无法解析多部分 servlet 请求;嵌套异常是 java.io.IOException: org.apache.tomcat.util.http .fileupload.FileUploadException: 请求被拒绝,因为没有找到多部分边界”。

阅读this后,我们尝试在fetch中设置headers的边界:

fetch("http://localhost:8910/taskCreationController/createStoryTask", {
      mode: 'no-cors',
      method: "POST",
      headers: {
        "Content-Type": "multipart/form-data; boundary=AaB03x" +
        "--AaB03x" +
        "Content-Disposition: file" +
        "Content-Type: png" +
        "Content-Transfer-Encoding: binary" +
        "...data... " +
        "--AaB03x--",
        "Accept": "application/json",
        "type": "formData"
      },
      body: data
    }).then(function (res) {
      if (res.ok) {
        alert("Perfect! ");
      } else if (res.status == 401) {
        alert("Oops! ");
      }
    }, function (e) {
      alert("Error submitting form!");
    });
  }

这一次,后端的错误是:Servlet.service() for servlet [dispatcherServlet] in context with path [] throw exception [Request processing failed;嵌套异常是 java.lang.NullPointerException] 的根本原因

我们添加多部分边界对吗?它应该在哪里? 也许我们一开始是错的,因为我们没有得到 multipart/form-data。怎样才能正确获取呢?

【问题讨论】:

    标签: reactjs file-upload multipartform-data


    【解决方案1】:

    我们只是尝试删除我们的标题并且它有效!

    fetch("http://localhost:8910/taskCreationController/createStoryTask", {
          mode: 'no-cors',
          method: "POST",
          body: data
        }).then(function (res) {
          if (res.ok) {
            alert("Perfect! ");
          } else if (res.status == 401) {
            alert("Oops! ");
          }
        }, function (e) {
          alert("Error submitting form!");
        });
    

    【讨论】:

    • 你如何在后端处理这些数据?假设 php @PeterJiang
    • 我们用的不是Php,而是Java
    【解决方案2】:

    这是我通过 axios 预览图片上传的解决方案。

    import React, { Component } from 'react';
    import axios from "axios";
    

    React 组件类:

    class FileUpload extends Component {
    
        // API Endpoints
        custom_file_upload_url = `YOUR_API_ENDPOINT_SHOULD_GOES_HERE`;
    
    
        constructor(props) {
            super(props);
            this.state = {
                image_file: null,
                image_preview: '',
            }
        }
    
        // Image Preview Handler
        handleImagePreview = (e) => {
            let image_as_base64 = URL.createObjectURL(e.target.files[0])
            let image_as_files = e.target.files[0];
    
            this.setState({
                image_preview: image_as_base64,
                image_file: image_as_files,
            })
        }
    
        // Image/File Submit Handler
        handleSubmitFile = () => {
    
            if (this.state.image_file !== null){
    
                let formData = new FormData();
                formData.append('customFile', this.state.image_file);
                // the image field name should be similar to your api endpoint field name
                // in my case here the field name is customFile
    
                axios.post(
                    this.custom_file_upload_url,
                    formData,
                    {
                        headers: {
                            "Authorization": "YOUR_API_AUTHORIZATION_KEY_SHOULD_GOES_HERE_IF_HAVE",
                            "Content-type": "multipart/form-data",
                        },                    
                    }
                )
                .then(res => {
                    console.log(`Success` + res.data);
                })
                .catch(err => {
                    console.log(err);
                })
            }
        }
    
    
        // render from here
        render() { 
            return (
                <div>
                    {/* image preview */}
                    <img src={this.state.image_preview} alt="image preview"/>
    
                    {/* image input field */}
                    <input
                        type="file"
                        onChange={this.handleImagePreview}
                    />
                    <label>Upload file</label>
                    <input type="submit" onClick={this.handleSubmitFile} value="Submit"/>
                </div>
            );
        }
    }
    
    export default FileUpload;
    

    【讨论】:

    • 直截了当!并感谢 base64 的添加。
    • 很高兴知道你喜欢它@mrKindo
    • base64 在这里做什么?当我 console.log 我得到以下我不明白的东西blob:http://localhost:3000/7454bf5a-e458-4c30-bbcc-ac0674ade821
    • @RobyCigar Base64 用于传输数据而不会丢失或修改内容本身。它是一种将二进制数据编码为 ASCII 字符集的方法。
    【解决方案3】:

    该文件在活动中也可用:

    e.target.files[0]
    

    (无需document.querySelector('input[type="file"]').files[0];

    uploadAction(e) {
      const data = new FormData();
      const imagedata = e.target.files[0];
      data.append('inputname', imagedata);
      ...
    

    注意: 使用console.log(data.get('inputname'))进行调试,console.log(data)不会显示附加数据。

    【讨论】:

    • 感谢 console.log(data.get('inputname'))。但是为什么 console.log(data) 会返回空呢?对于多个文件,我正在使用 console.log(data.getAll('inputname'))
    【解决方案4】:

    https://muffinman.io/uploading-files-using-fetch-multipart-form-data/ 最适合我。它使用 formData。

    import React from "react";
    import logo from "./logo.svg";
    import "./App.css";
    import "bootstrap/dist/css/bootstrap.min.css";
    import Button from "react-bootstrap/Button";
    
    const ReactDOM = require("react-dom");
    
    
    export default class App extends React.Component {
      constructor(props) {
        super(props);
        this.test = this.test.bind(this);
        this.state = {
          fileUploadOngoing: false
        };
      }
    
      test() {
        console.log(
          "Test this.state.fileUploadOngoing=" + this.state.fileUploadOngoing
        );
        this.setState({
          fileUploadOngoing: true
        });
    
        const fileInput = document.querySelector("#fileInput");
        const formData = new FormData();
    
        formData.append("file", fileInput.files[0]);
        formData.append("test", "StringValueTest");
    
        const options = {
          method: "POST",
          body: formData
          // If you add this, upload won't work
          // headers: {
          //   'Content-Type': 'multipart/form-data',
          // }
        };
        fetch("http://localhost:5000/ui/upload/file", options);
      }
      render() {
        console.log("this.state.fileUploadOngoing=" + this.state.fileUploadOngoing);
        return (
          <div>
            <input id="fileInput" type="file" name="file" />
            <Button onClick={this.test} variant="primary">
              Primary
            </Button>
    
            {this.state.fileUploadOngoing && (
              <div>
                <h1> File upload ongoing abc 123</h1>
                {console.log(
                  "Why is it printing this.state.fileUploadOngoing=" +
                    this.state.fileUploadOngoing
                )}
              </div>
            )}
    
          </div>
        );
      }
    }
    

    【讨论】:

      【解决方案5】:

      React 文件上传组件

      import { Component } from 'react';
      
      class Upload extends Component {
        constructor() {
          super();
          this.state = {
            image: '',
          }
        }
      
        handleFileChange = e => {
          this.setState({
            [e.target.name]: e.target.files[0],
          })
        }
      
        handleSubmit = async e => {
          e.preventDefault();
      
          const formData = new FormData();
          for (let name in this.state) {
            formData.append(name, this.state[name]);
          }
      
          await fetch('/api/upload', {
            method: 'POST',
            body: formData,
          });
      
          alert('done');
        }
      
        render() {
          return (
            <form onSubmit={this.handleSubmit}>
              <input 
                name="image" 
                type="file"
                onChange={this.handleFileChange}>
              </input>
              <input type="submit"></input>
            </form>
          )
        }
      }
      
      export default Upload;
      

      【讨论】:

        【解决方案6】:

        对于发送multipart/formdata,您需要避免contentType,因为浏览器会自动分配boundaryContent-Type

        在您使用fetch 的情况下,即使您避免使用Content-Type,它也会设置为默认text/plain。所以尝试使用 jQuery ajax。如果我们将 contentType 设置为 false,它将删除它。

        这是工作代码

        var data = new FormData();
        var imagedata = document.querySelector('input[type="file"]').files[0];
        data.append("data", imagedata);
        $.ajax({
            method: "POST",
            url: fullUrl,
            data: data,
            dataType: 'json',
            cache: false,
            processData: false,
            contentType: false
        }).done((data) => {
            //resolve(data);
        }).fail((err) => {
            //console.log("errorrr for file upload", err);
            //reject(err);
        });
        

        【讨论】:

        • jQuery 中针对 ReactJS 问题的示例只是没有抓住重点。
        • @lilly 您可以使用import $ from 'jquery'React 中使用jQuery ajax。希望这是有道理的。
        • 我认为他不想为此使用 jQuery @JyothiBabuAraja
        • 您只是想通过这些建议严重解决 cors 问题。
        • @DevDonkey,对不起,我刚刚给出了一种通过 XHR 发送多部分表单数据的方法。我在这里无处解决 CORS 问题。如果您有任何编辑,请始终打开以供编辑。