16

I have an uploader that allows a user to upload several pictures. In order to only create or update the images he wants to add/change, I update an object that looks like this:

{main: Blob, "1": Blob, "2":Blob}

So if only needs to update "1" later, the sent object will only contain {"1": Blob}

When clicking on save, it triggers a function that is supposed to append the images to a formData(). Sadly the formData is never updated. I have the following error:

Failed to execute 'append' on 'FormData': parameter 2 is not of type 'Blob'.

export async function uploadImages(files, userId) {
  try {
    const images = new FormData();
    files.main && images.append("image", files.main, "main");
    files[1] && images.append("image", files[1], "1");
    files[2] && images.append("image", files[2], "2");

    const res = await ax.post(process.env.SERVER_URL + "/upload-images", {
      images,
      userId,
    });
    return "success"
  } catch (err) {
    return "error"
  }
}

How to fix this? Thanks!

4 Answers 4

3

You should not be able to see FormData object contents in console, because its not serializable. You can check request payload instead, check "Network" tab in your browser dev tools, find your request and look at the bottom of "Headers" tab to see "FormData" log. You will see something like this: enter image description here

Also, you should set header "Content-Type" to "multipart/form-data" in axios. Here is working example:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  </head>
  <body>
    <input type="file" multiple id="filepicker" />

    <button id="send">Send</button>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.20.0/axios.min.js"></script>
    <script>
      const myformData = new FormData();

      document
        .querySelector('#filepicker')
        .addEventListener('change', function (event) {
          const { files } = event.target;

          Object.values(files).forEach(function (file, index) {
            myformData.append(index, file);
          });
        });

      document.querySelector('#send').addEventListener('click', function () {
        axios({
          method: 'post',
          url: 'http://google.com',
          data: myformData,
          headers: { 'Content-Type': 'multipart/form-data' },
        })
          .then((response) => console.log(response))
          .catch((err) => console.log(err));
      });
    </script>
  </body>
</html>

7
  • I actually log the images formData when when receiving the request in my node server. I thought I could see it through req.body.images. By doing your method, I receive the error "Error: Multipart: Boundary not found at new Multipart".
    – DoneDeal0
    Commented Sep 24, 2020 at 19:43
  • I just checked and it works. If you are using Node.js and Express, then you probably missing middleware for handling file uploads, check this answer
    – pearcake
    Commented Sep 24, 2020 at 19:54
  • But I already have bodyparser and multer to handle data parsing, do I need to install busboy as well?!
    – DoneDeal0
    Commented Sep 24, 2020 at 20:45
  • If you already have multer, then you dont need to install busboy (since multer uses busboy as a dependency). It means that there is something wrong with your code logic. You can use code snippet from the answer I linked above, or create a new question, since backend logic is not related to FormData question.
    – pearcake
    Commented Sep 24, 2020 at 21:24
  • Ok I've finally found the mistake: I was trying to access the data through req.body and not req.file... It works now. However, I still need to send the user id as well in the same post request. Would you know how to do it?
    – DoneDeal0
    Commented Sep 24, 2020 at 21:36
3

I faced this issue on my react native app. To solve it I had to convert the image path to a blob. The code for my handle upload function is given below.

const handleUpload = async () => {
    if (selectedImage.localUri !== '') {

        const image_uri =  Platform.OS === 'ios' ? selectedImage.localUri.replace('file://', '') : selectedImage.localUri;

        const response = await fetch(image_uri);
        const blob = await response.blob();

        const formData = new FormData();
        formData.append('image', blob, "xray_image.jpg");
  
        setLoading(true);

        axios.post("https://...", formData)
            .then((result) => {
               console.log(result);
            })
            .catch((err) => {
                console.log(err);
              
            });

    } else {
        console.log("Select a file error message");
    }
};
0
export async function uploadImages(files, userId) {
  try {
    const images = new FormData();
    for(const file of files){
        images.append("image", file);
    }
    const res = await ax.post(process.env.SERVER_URL + "/upload-images", {
      images,
      userId,
    });
    return "success"
  } catch (err) {
    return "error"
  }
}
1
  • The formData is still empty.
    – DoneDeal0
    Commented Sep 24, 2020 at 18:03
-3

you have to pass the extension along with the name

files[1] && images.append("image", files[1], "custom-name.jpg");

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.