Send Blob file via Axios

I have object like this:

{
    "name": "filename",
    "size": 3523507,
    "type": "image/png",
    "extension": "png",
    "url": "blob:http://localhost:8081/082e9c22-9869-4289-a9c8-e36b0640e61c"
}

And i need upload it to backend. I try it:

const session = axios.create({
  baseURL: debug ? 'http://localhost:8000': '',
  xsrfCookieName: CSRF_COOKIE_NAME,
  xsrfHeaderName: CSRF_HEADER_NAME,
});
let formData = new FormData();
formData.append('file', file, 'file.name');

return session.post(`/chats/files/`,{...formData},), {
  headers: {
    "Content-Type": `multipart/form-data`,
  }
}

But it doesn't work to add Blob to the formData

UPD I get an object with files from the send-message method in the vue-advanced-chat component in this form:

{
    "name": "filename",
    "size": 3523507,
    "type": "image/png",
    "extension": "png",
    "localUrl": "blob:http://localhost:8081/aae047a9-5f9e-481f-b0cc-17febe954c31",
    "blob": {}
}

Then I format it to display in the interface before uploading to the server

UPD2

I converted blob to file

send_file(roomId, messageId, blob_file, isAudio, duration) {
        let formData = new FormData();
        let file = new File([blob_file.blob], blob_file.name);
        formData.append('file[]', file, blob_file.name);
        return session.post(`/chats/files/`,
            {'chat': roomId, 'message': messageId, ...formData},), {
            headers: {
              'Content-Type': `multipart/form-data; boundary=${formData._boundary}`,
            },
            timeout: 30000,
        }
    },

and still get: {"file":["No files were sent."]}

Upvotes: 8

Views: 18552

Answers (3)

I came to this question and after a few hours, here are my findings and solutions. First, I realized binary data like blobs cannot be send through json. Axios normally sends its data as json and hence, nothing would be received on the backend. Here setting the header was required:

      const data = new FormData();
      data.append("username", "Chris");
      data.append("file", userAnswers[0].value);

      let apiEndPoint = "/api/plans/answer/speaking/" + planId;
      axiosInstance
        .post(apiEndPoint, data, {
          headers: {
            "Content-Type": `multipart/form-data; boundary=${data._boundary}`,
          },
          timeout: 30000,
        })
        .then(() => {
          toast({
            title: `Submitted`,
            status: "success",
            isClosable: true,
          });
          navigate("/");
        })

We see the use of FormData as well. It is necessary. Maybe you created a form and mentioned the type there. I wasn't using a form.

<form action="/stats" enctype="multipart/form-data" method="post">

The second important part was handling the backend. The frontend part is not enough. Multer middleware is required. optional relevance

const multer = require("multer");
const upload = multer({ dest: "./public/data/uploads/" });

router.post(
  "/answer/speaking/:id",
  [auth, validateObjectId, upload.single("file")],
  async (req, res) => {
    winston.info(req.file);
    winston.info(req.body);
    res.send();
    return;
})

optional output of code

Upvotes: -1

After several days of searching, debugging and dozens of attempts, I managed to find a solution.

  1. You need a Blob object, not a URL
  2. You need to convert Blob to File let file = new File([blob_file.blob], fileName);
  3. To correctly identify the file type, you need to add blob_file.extension to the name let fileName = `${blob_file.name}.${blob_file.extension}`;
  4. You need to add all attributes to formData
formData.append('file', file, fileName);
formData.append('chat', roomId);
formData.append('message', messageId);
  1. Specify 'Content-Type': multipart/form-data, and don't specify _boundary - because in new versions of formData it is determined automatically!
headers: {
   'Content-Type': `multipart/form-data`,
},

so the final version of the code looks like this:

send_file(roomId, messageId, blob_file) {
    let formData = new FormData();
    let fileName = `${blob_file.name}.${blob_file.extension}`;
    let file = new File([blob_file.blob], fileName);
    formData.append('file', file, fileName);
    formData.append('chat', roomId);
    formData.append('message', messageId);

    return session.post(`/chats/files/`,
        formData, {
           headers: {
             'Content-Type': `multipart/form-data`,
           },
        })

Upvotes: 11

Mr. Dev
Mr. Dev

Reputation: 81

You are not sending data in correct way. It should be:

export const uploadFileRequest = ({ file }) => {
   const data = new FormData();
   data.append('file', file, file.name);

   return session.post(`/chats/files/`, data, {
     headers: {
       'Content-Type': `multipart/form-data;boundary=${data._boundary}`,
     },
     timeout: 30000,
   });
};

it should work, for reference https://medium.com/@fakiolinho/handle-blobs-requests-with-axios-the-right-way-bb905bdb1c04

Upvotes: 0

Related Questions