How to post a file from a form with Axios
Asked Answered
W

10

311

Using raw HTML when I post a file to a flask server using the following I can access files from the flask request global:

<form id="uploadForm" action='upload_file' role="form" method="post" enctype=multipart/form-data>
    <input type="file" id="file" name="file">
    <input type=submit value=Upload>
</form>

In flask:

def post(self):
    if 'file' in request.files:
        ....

When I try to do the same with Axios the flask request global is empty:

<form id="uploadForm" enctype="multipart/form-data" v-on:change="uploadFile">
<input type="file" id="file" name="file">
</form>

uploadFile: function (event) {
    const file = event.target.files[0]
    axios.post('upload_file', file, {
        headers: {
          'Content-Type': 'multipart/form-data'
        }
    })
}

If I use the same uploadFile function above but remove the headers json from the axios.post method I get in the form key of my flask request object a csv list of string values (file is a .csv).

How can I get a file object sent via axios?

Wexford answered 25/3, 2017 at 7:45 Comment(3)
@Niklesh yes typo cutting and pasting, I fixed it above, includes double quotes in code.Wexford
did you tried v-on:change="uploadFile" with input instead of form tag ?Aalborg
@Niklesh I get same result - data sent as string and picked up by request.form not request.files in flask.Wexford
A
583

Add the file to a formData object, and set the Content-Type header to multipart/form-data.

var formData = new FormData();
var imagefile = document.querySelector('#file');
formData.append("image", imagefile.files[0]);
axios.post('upload_file', formData, {
    headers: {
      'Content-Type': 'multipart/form-data'
    }
})
Aalborg answered 25/3, 2017 at 8:16 Comment(8)
After posting the files. Do we need to access them from HTTP request or need to access them from parameters on server side.Pommel
@ParthPatel : I am using $_FILES to get files in server side as I am using PHPAalborg
Thanks for this post, but I still don't see why we need FormData. According to axios's doc, both File and FormData are treated as Browser only, so both ways can be seen equally (github.com/axios/axios#request-config)Classify
Awesome ! I was sending 'data:{ data:formData}' which was generating error 412. It worked with data:formDataBarnard
ATTENTION: the snippet works as-is when run in the context of a browser. To run in node.js, one needs to pass the headers computed by formData.getHeaders() This is a known issue with axios; see for e.g. https://github.com/axios/axios/issues/789Von
@RishiRaut, may I ask you to have a look at an axios related question here : #59470585 ?Paunchy
About the comment by @Classify on File vs. FormData: correct me if I'm wrong, but I believe File can be used only if you're uploading a single file and not including any other payload data in the request (like in the answer), but FormData is what you'll have to use if you want to submit a collection of data (that is, a form with several fields) in addition to the file(s) (which I suspect is more often the case in real applications).Bijection
Thanks for the solution. After upgrading Axios from 0.26 to new major 1.4.0, we started experiencing this issue when sending images to api. Super strange as our image upload features "all of a sudden" stopped working...Scherer
C
32

Sample application using Vue. Requires a backend server running on localhost to process the request:

var app = new Vue({
  el: "#app",
  data: {
    file: ''
  },
  methods: {
    submitFile() {
      let formData = new FormData();
      formData.append('file', this.file);
      console.log('>> formData >> ', formData);

      // You should have a server side REST API 
      axios.post('http://localhost:8080/restapi/fileupload',
          formData, {
            headers: {
              'Content-Type': 'multipart/form-data'
            }
          }
        ).then(function () {
          console.log('SUCCESS!!');
        })
        .catch(function () {
          console.log('FAILURE!!');
        });
    },
    handleFileUpload() {
      this.file = this.$refs.file.files[0];
      console.log('>>>> 1st element in files array >>>> ', this.file);
    }
  }
});

https://codepen.io/pmarimuthu/pen/MqqaOE

Conjunctive answered 15/9, 2018 at 19:44 Comment(0)
B
30

If you don't want to use a FormData object (e.g. your API takes specific content-type signatures and multipart/formdata isn't one of them) then you can do this instead:

uploadFile: function (event) {
    const file = event.target.files[0]
    axios.post('upload_file', file, {
        headers: {
          'Content-Type': file.type
        }
    })
}
Brader answered 28/10, 2020 at 22:44 Comment(1)
If you use PUT to upload file then you may use application/octet-stream as Content-Type. If you upload into Amazon S3 storage using multipart/formdata as Content-Type it will make your files (images, pdfs, documents) into text files with http header added on top. This will damage the content of the uploaded file. So use application/octet-stream when uploading binary files with PUT methods.Untinged
S
20

Sharing my experience with React & HTML input

Define input field

<input type="file" onChange={onChange} accept ="image/*"/>

Define onChange listener

const onChange = (e) => {
  let url = "https://<server-url>/api/upload";
  let file = e.target.files[0];
  uploadFile(url, file);
};

const uploadFile = (url, file) => {
  let formData = new FormData();
  formData.append("file", file);
  axios.post(url, formData, {
      headers: {
        "Content-Type": "multipart/form-data",
      },
    }).then((response) => {
      fnSuccess(response);
    }).catch((error) => {
      fnFail(error);
    });
};
const fnSuccess = (response) => {
  //Add success handling
};

const fnFail = (error) => {
  //Add failed handling
};
Siskind answered 6/4, 2021 at 7:15 Comment(0)
C
15

This works for me, I hope helps to someone.

var frm = $('#frm');
let formData = new FormData(frm[0]);
axios.post('your-url', formData)
    .then(res => {
        console.log({res});
    }).catch(err => {
        console.error({err});
    });
Calen answered 18/3, 2020 at 19:31 Comment(2)
using Nuxt - this finally worked for me. removing headers: { 'Content-Type': 'multipart/form-data' } was the only way it would actually send the post after getting a server response from options. I am probably doing something wrong, but it is working and I'm leaving it alone lolChronicles
@JeffBluemel Content-Type headers are set automagically. You are supposed to have those undefined.Shenyang
C
7

this is my way:

var formData = new FormData(formElement);
// formData.append("image", imgFile.files[0]);
const res = await axios.post(
  "link-handle",
  formData,
  {
    headers: {
      "Content-Type": "multipart/form-data",
    },
  }
);
Commissioner answered 14/8, 2022 at 8:6 Comment(0)
V
1

How to post file using an object in memory (like a JSON object):

import axios from 'axios';
import * as FormData  from 'form-data'

async function sendData(jsonData){
    // const payload = JSON.stringify({ hello: 'world'});
    const payload = JSON.stringify(jsonData);
    const bufferObject = Buffer.from(payload, 'utf-8');
    const file = new FormData();

    file.append('upload_file', bufferObject, "b.json");

    const response = await axios.post(
        lovelyURL,
        file,
        headers: file.getHeaders()
    ).toPromise();


    console.log(response?.data);
}
Vergeboard answered 24/9, 2020 at 15:53 Comment(0)
P
1

There is an issue with Axios version 0.25.0 > to 0.27.2 where FormData object in a PUT request is not handled correctly if you have appended more than one field but is fine with one field containing a file, POST works fine.

Also Axios 0.25.0+ automatically sets the correct headers so there is no need to specify Content-Type.

Phoebe answered 27/9, 2022 at 12:13 Comment(0)
S
-1

if you are taking a picture, you have to store the image and keep its route, then retrieve its blob on the machine from its route, add the blob to the formData By adding also the name of the image, then make the request with the multipart/form-data header, and we find the image in the back inside req.files

Saviour answered 22/4 at 4:28 Comment(0)
A
-2

For me the error was the actual parameter name in my controller... Took me a while to figure out, perhaps it will help someone. Im using Next.js / .Net 6

Client:

export const test = async (event: any) => {
    const token = useAuthStore.getState().token;
    console.log(event + 'the event')
    if (token) {
        const formData = new FormData();
        formData.append("img", event);
        const res = await axios.post(baseUrl + '/products/uploadproductimage', formData, {
            headers: {
                'Authorization': `bearer ${token}`
            }
        })
        return res
    }
    return null
}

Server:

 [HttpPost("uploadproductimage")]
        public async Task<ActionResult> UploadProductImage([FromForm] IFormFile image)
        {
            return Ok();
        }

Error here because server is expecting param "image" and not "img:

formData.append("img", event);

 public async Task<ActionResult> UploadProductImage([FromForm] IFormFile image)
Arin answered 28/1, 2022 at 20:7 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.