React - 上传到 Spring API 的第一个文件不起作用,再试一次,第二次尝试是否正常?

React - 1st file upload to Spring API doesn't work, try again and it works fine on second try?

你好

我开发了一个前端 React 项目,它向 SpringBoot REST API 请求资源和逻辑。我最近实现了文件上传,我使用 React 创建的表单在第一次尝试时总是失败,但是当我再次单击它并上传另一个文件时(哪个文件无关紧要,不是文件导致的),它成功上传了通过 POST 以二进制文件作为有效载荷的文件。

第一个请求的负载为 'undefined'。

反应形式:

const UPDATE_USER_URL = 'http://localhost:8080/users/update-user-details';
const UPLOAD_FILE_URL = 'http://localhost:8080/image-files';
class UpdateUserForm extends React.Component {

    constructor(props) {
        super(props);
        this.state = {
            username: localStorage.getItem("username"),
            location: "",
            bio: ""
        };
        this.onSubmit = this.onSubmit.bind(this);

        this.handleInputChange = this.handleInputChange.bind(this);
    }

    handleInputChange(event) {
        const target = event.target;
        const value = target.value;
        const name = target.name;

        this.setState({
            [name]: value
        });
    }

    onFileChangeHandler = (e) => {
        e.preventDefault();
        this.setState({
            selectedFile: e.target.files[0]
        });
        const formData = new FormData();
        formData.append('file', this.state.selectedFile);
        const USER_UPLOAD_FILE_URL = UPLOAD_FILE_URL + "/" + this.state.username;
        fetch(USER_UPLOAD_FILE_URL, {
            method: 'POST',
            headers: {
                "Authorization": localStorage.getItem("token")
            },
            body: formData
        }).then(res => {
            if(res.ok) {
                console.log(res.data);
                alert("File uploaded successfully.")
            }
        });

    };

    onSubmit(event) {
        event.preventDefault();
        const payload = {
            "username": this.state.username,
            "location": this.capital_letter(this.state.location),
            "bio": this.state.bio
        };

        fetch(UPDATE_USER_URL, {
            method: 'PUT',
            headers: {
                "Accept": "application/json",
                "Content-Type": "application/json",
                "Authorization": localStorage.getItem("token")
            },
            body: JSON.stringify(payload)
        })
            .then(response => response.json())
            .then((data) => {
                console.log(data);
            });
    }
    //https://www.w3resource.com/javascript-exercises/javascript-basic-exercise-50.php
    capital_letter(str) {

        str = str.split(" ");

        for (var i = 0, x = str.length; i < x; i++) {
            str[i] = str[i][0].toUpperCase() + str[i].substr(1);
        }
        console.log(str)
        return str.join(" ");
    }

    generateUploadUrl(username) {

    }

    render() {
        return (
            <div className="outer-div-container">
                <div>
            <AppNavbar/>
            <div id="form-container">
                <div id="form-div">

                    <h5 id="form-heading">Update Details</h5>
                    <br />
            <div className="outer-div-container">
            <form onSubmit={this.onSubmit}>
                <label className="form-label" id="top-form-label">
                    Location:
                    <br />
                    <input
                        className="form-input"
                        //Taumatawhakatangihangakoauauotamateaturipukakapikimaungahoronukupokaiwhen
                        maxLength="85"
                        //No min length as places with 1 letter e.g: A, S.
                        name="location"
                        type="text"
                        value={this.state.location}
                        onChange={this.handleInputChange} />
                </label>
                <br />
                <label className="form-label">
                    Bio:
                    <br />
                    <input
                        className="form-input"
                        minLength="3"
                        name="bio"
                        type="text"
                        value={this.state.bio}
                        onChange={this.handleInputChange} />
                </label>
                <label>Upload Your File </label>
                <input type="file" className="form-control" name="file" onChange={this.onFileChangeHandler}/>

                <br />
                <input id="form-submit" type="submit" value="Submit" />

            </form>
                <div className="form-group files color">
                        <label>Upload Your File </label>
                        <input type="file" className="form-control" name="file" onChange={this.onFileChangeHandler}/>
                </div>
            </div>
            </div>
                </div>
            </div>
            </div>
        );
    }
}
export default UpdateUserForm;

控制器:

@RestController
@RequestMapping("image-files")
@AllArgsConstructor
@CrossOrigin("*")
public class ImageFileController {
    ImageFileService service;


    @GetMapping(value = "/{username}")
    public byte[] downloadImageFile(@PathVariable String username) {
        return service.downloadImageFile(username);
    }
}

非常感谢任何帮助,我完全被难住了,谢谢。

在您的 onFileChangeHandler 函数中,您将文件设置为 selectedFile 状态,然后像

一样立即再次访问它
formData.append('file', this.state.selectedFile);

你不能将某些东西设置为反应状态并在下一行再次访问它,这是因为 setState 在反应中异步工作。这意味着如果你想从反应状态中获取最新的设置值,你需要等待下一次重新渲染发生。否则,您将只能从状态中获取先前设置的值,在您的情况下为 undefined。所以在你的函数中,将文件数据直接传递给formData。试试下面的代码

onFileChangeHandler = (e) => {
    e.preventDefault();
    const fileData = e.target.files[0];
    this.setState({
        selectedFile: fileData
    });
    const formData = new FormData();
    formData.append('file', fileData);
    const USER_UPLOAD_FILE_URL = UPLOAD_FILE_URL + "/" + this.state.username;
    fetch(USER_UPLOAD_FILE_URL, {
        method: 'POST',
        headers: {
            "Authorization": localStorage.getItem("token")
        },
        body: formData
    }).then(res => {
        if(res.ok) {
            console.log(res.data);
            alert("File uploaded successfully.")
        }
    });

};