简体   繁体   中英

React frontend sending image to fastapi backend

Frontend = React, backend = FastApi. How can I simply send an image from the frontend, and have the backend saving it to the local disk? I've tried different ways: in an object, in a base64 string, etc. But I can't manage to deserialize the image in FastApi. It looks like an encoded string, I tried writing it to a file, or decoding it, but with no success.

const [selectedFile, setSelectedFile] = useState(null);
const changeHandler = (event) => {setSelectedFile(event.target.files[0]);   };
const handleSubmit = event => {

const formData2 = new FormData();
formData2.append(
"file",
selectedFile,
selectedFile.name
);

const requestOptions = {
    method: 'POST',
    headers: { 'Content-Type': 'multipart/form-data' },
    body: formData2 // Also tried selectedFile
};
  fetch('http://0.0.0.0:8000/task/upload_image/'+user_id, requestOptions)
    .then(response => response.json())
}

return (  <div
            <form onSubmit={handleSubmit}>
              <fieldset>
                  <label htmlFor="image">upload picture</label><br/>
                  <input name="image" type="file" onChange={changeHandler} accept=".jpeg, .png, .jpg"/>

              </fieldset>
              <br/>
              <Button color="primary" type="submit">Save</Button>
            </form>
</div>
);

And the backend:

@router.post("/upload_image/{user_id}")
async def upload_image(user_id: int, request: Request):
    body = await request.body()
    
    # fails (TypeError)
    with open('/home/backend/test.png', 'wb') as fout:
        fout.writelines(body) 

I also tried to simply mimic the client with something like this: curl -F media=@/home/original.png http://0.0.0.0:8000/task/upload_image/3 but same result...

----- [Solved] Removing user_id for simplicity. The server part must look like this:

@router.post("/uploadfile/")
async def create_upload_file(file: UploadFile = File(...)):
    out_path = 'example/path/file'
    async with aiofiles.open(out_path, 'wb') as out_file:
        content = await file.read()
        await out_file.write(content)

And for some reason, the client part should not include the content-type in the headers:

function TestIt ( ) {
    const [selectedFile, setSelectedFile] = useState(null);
    const [isFilePicked, setIsFilePicked] = useState(false);
  
    const changeHandler = (event) => {
        setSelectedFile(event.target.files[0]);
        setIsFilePicked(true);
    };
    
    const handleSubmit = event => {
      event.preventDefault();
      const formData2 = new FormData();
      formData2.append(
        "file",
        selectedFile,
        selectedFile.name
      );
      
    const requestOptions = {
        method: 'POST',
        //headers: { 'Content-Type': 'multipart/form-data' }, // DO NOT INCLUDE HEADERS
        body: formData2
    };
      fetch('http://0.0.0.0:8000/task/uploadfile/', requestOptions)
        .then(response => response.json())
        .then(function (response) {
          console.log('response')
          console.log(response)
            });
    }
    return (  <div>
        <form onSubmit={handleSubmit}>
          <fieldset>
              <input name="image" type="file" onChange={changeHandler} accept=".jpeg, .png, .jpg"/>
          </fieldset>
          <Button type="submit">Save</Button>
        </form>
    </div>
  );
}

Replying from to your comment: yes there is a simple snippet example of JS-Fastapi and it was answered by me not long ago.

The reason you are not able to access the file is fairly simple: the naming of the python parameters must match the keys of the formData object.

Instead, you are accessing the raw request, which does not make sense.

Simply change your python code as follows:

from fastapi import UploadFile, File

@router.post("/upload_image/{user_id}")
async def upload_image(user_id: int, file: UploadFile = File(...)):
    # Your code goes here

which is well detailed in the official docs

https://fastapi.tiangolo.com/tutorial/request-files/?h=file

FYI

The following are the references to my answers (actually checking, I answered multiple questions related to this topic and should be enough to understand the basic problems one may fall into when uploading files)

How to send a file (docx, doc, pdf or json) to fastapi and predict on it without UI (ie, HTML)?

How can I upload multiple files using JavaScript and FastAPI?

How to upload file using fastapi with vue? I got error unprocessable 422

Uploading an excel file to FastAPI from a React app

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM