You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React图片上传组件对接API遇422错误:文件需嵌套请求体

Solution for React File Upload with Nested Backend Request Structure

Hey there! I see you're stuck on getting your file upload to work with that nested request structure your backend expects. Let's break down what's going wrong and fix it step by step.

The Root of the Problem

Your backend is expecting a multipart/form-data request with nested parameters (like course[attachment_attributes][file]), but your previous attempts either:

  1. Only sent the file without the rest of the course fields, or
  2. Tried to stuff a FormData object into a JSON body (which doesn't work—JSON can't serialize binary file data, so the backend just sees [object FormData] instead of the actual file, hence the attachment.file blank error).

The Fix: Build a FormData with Nested Parameter Names

Instead of mixing JSON and FormData, we'll construct a single FormData object that matches the exact structure your backend is looking for. We use bracket notation (course[title], course[attachment_attributes][file]) to represent the nested fields.

Here's the updated onClickHandler code:

onClickHandler = () => {
  const formData = new FormData();
  
  // Append all course fields using nested parameter names
  formData.append('course[title]', 'Hic et velit sed.');
  formData.append('course[subtitle]', 'Omnis quibusdam illum itaque.');
  formData.append('course[description]', 'Et ullam ipsum. Illum dolor odit. Id veritatis ducimus.');
  formData.append('course[end_date]', '2020-02-01');
  
  // Append the file to the nested attachment_attributes field
  if (this.state.selectedFile) {
    formData.append('course[attachment_attributes][file]', this.state.selectedFile);
  }

  return api
    .post("http://localhost:3000/api/v1/files", formData)
    .then(res => { console.log("Upload successful!", res.statusText) })
    .catch(err => console.log('Upload error ==> ', err.response?.data || err))
}

Why This Works

  • When you use formData.append('course[attachment_attributes][file]', file), it tells the backend to map the file to the exact nested location it expects (course.attachment_attributes.file).
  • Most HTTP clients (like Axios, which I assume your api helper uses) automatically set the correct Content-Type: multipart/form-data header when you pass a FormData object, so you don't need to manually set it.

Important Notes

  1. Check Your API Helper: Make sure your api instance isn't forcing a Content-Type: application/json header globally. If it is, you'll need to override it for this request, or remove the global setting for uploads. For Axios, you can do this by adding headers: { 'Content-Type': 'multipart/form-data' } to the post call (though usually Axios handles this automatically).
  2. Single vs Multiple Files: Your input has multiple set, but your state only stores selectedFile (single file). If you need to upload multiple files, you'll need to loop through event.target.files and append each one with the same parameter name (some backends expect an array like course[attachment_attributes][file][] for multiple files).

Full Updated Component Code

Here's the complete component with the fix applied:

import React, { Component } from 'react';
import api from '../../../../helpers/API';

class Uploader extends Component {
  constructor(props) {
    super(props);
    this.state = { selectedFile: null }
  }

  onChangeHandler = event => {
    // If using multiple files, you'd store an array here instead
    this.setState({ selectedFile: event.target.files[0], loaded: 0 })
  }

  onClickHandler = () => {
    const formData = new FormData();
    
    // Append course fields
    formData.append('course[title]', 'Hic et velit sed.');
    formData.append('course[subtitle]', 'Omnis quibusdam illum itaque.');
    formData.append('course[description]', 'Et ullam ipsum. Illum dolor odit. Id veritatis ducimus.');
    formData.append('course[end_date]', '2020-02-01');
    
    // Append file if selected
    if (this.state.selectedFile) {
      formData.append('course[attachment_attributes][file]', this.state.selectedFile);
    }

    return api
      .post("http://localhost:3000/api/v1/files", formData)
      .then(res => { console.log("Upload successful!", res.statusText) })
      .catch(err => console.log('Upload error ==> ', err.response?.data || err))
  }

  render() {
    return (
      <>
        <div>
          <label>Upload Your File </label>
          <input type="file" multiple onChange={this.onChangeHandler}/>
        </div>
        <button type="button" className="btn btn-success btn-block" onClick={this.onClickHandler}>Upload</button>
      </>
    )
  }
}

export default Uploader

Give this a try—your backend should now correctly receive the course data and the file, and the 422 error should disappear!

内容的提问来源于stack exchange,提问作者Joe

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 17:53:09