sourcecode

React.js, 멀티파트/폼 데이터를 서버로 전송하는 방법

copyscript 2023. 3. 10. 22:41
반응형

React.js, 멀티파트/폼 데이터를 서버로 전송하는 방법

이미지 파일을 멀티파트/폼으로 백엔드에 송신하고 싶다.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>
    )
  }
}

백엔드의 오류는 "nosted exception is org.springframework.web.multipart.멀티파트예외: 다중 파트 서블릿 요청을 구문 분석할 수 없습니다. 중첩된 예외는 java.io입니다.IOException: org.apache.tomcat.util.http.fileupload.FileUploadException: 멀티파트 경계를 찾을 수 없어 요청이 거부되었습니다."

이것을 읽고 나서, fetch시에 헤더의 경계를 설정하려고 했습니다.

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!");
    });
  }

이 경우 백엔드의 오류는 경로 []를 사용한 예외 [Request processing failed; nested 예외는 java.lang]를 포함한 예외는 servlet [dispatcherServlet]의 Servlet.service()입니다.특수한 포인터근본 원인이 있는 예외]

멀티파트 경계를 올바르게 추가합니까?어디에 둬야 할까요?멀티파트/폼데이터를 입수할 수 없기 때문에 처음에는 틀렸을지도 모릅니다.어떻게 하면 맞힐 수 있을까요?

머리글만 없애면 돼!

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!");
    });

여기 악시스를 통한 미리보기와 함께 이미지를 업로드하기 위한 솔루션이 있습니다.

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

반응 컴포넌트 클래스:

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;

이 파일은 다음 이벤트에서도 사용할 수 있습니다.

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)는 추가된 데이터를 표시하지 않습니다.

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

응답 파일 업로드 구성 요소

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;

멀티파트 경계를 찾을 수 없었기 때문에 요청이 거부되었습니다."

보낼 때multipart/form-data경계는 요청 헤더의 콘텐츠유형에 자동으로 추가됩니다.파라미터가 경계규칙으로 끝나는 타이밍을 서버에 통지해야 합니다.설정하셔야 합니다.Content-type이것처럼.

"Content-Type": `multipart/form-data: boundary=add-random-characters`

이 기사에는 가이드도 포함되어 있습니다.https://roytuts.com/boundary-in-multipart-form-data/

경계는 다중 파트/폼 데이터의 이름/값 쌍을 구분하기 위해 포함됩니다.경계 매개변수는 다중 파트/폼 데이터의 각 이름과 값 쌍에 대한 마커와 같은 역할을 합니다.경계 파라미터는 http(Hyper Text Transfer Protocol) 요구 헤더의 Content-Type에 자동으로 추가됩니다.

★★★를 송신하기 multipart/formdata 돼요.contentType에 의해 할당되기 boundary ★★★★★★★★★★★★★★★★★」Content-Type.

의 경우, 「」를 사용해 .fetch「」를 Content-Type로 설정되어 .text/plain jQuery를 해 보세요.ajax★★★★★★★★★★★★★★★★,contentType짓으거

이것이 작업 코드입니다.

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

언급URL : https://stackoverflow.com/questions/41610811/react-js-how-to-send-a-multipart-form-data-to-server

반응형