300

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?

Emile Bergeron
  • 17,074
  • 5
  • 83
  • 129
Don Smythe
  • 9,234
  • 14
  • 62
  • 105

9 Answers9

564

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'
    }
})
davidism
  • 121,510
  • 29
  • 395
  • 339
Niklesh Raut
  • 34,013
  • 16
  • 75
  • 109
  • 2
    After posting the files. Do we need to access them from HTTP request or need to access them from parameters on server side. – Parth Patel Sep 01 '17 at 10:53
  • @ParthPatel : I am using `$_FILES` to get files in server side as I am using PHP – Niklesh Raut Sep 01 '17 at 11:02
  • 16
    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 (https://github.com/axios/axios#request-config) – Hiroki Dec 17 '17 at 06:12
  • 3
    Awesome ! I was sending 'data:{ data:formData}' which was generating error 412. It worked with `data:formData` – Aseem May 02 '19 at 00:55
  • 13
    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/789` – mjv May 30 '19 at 05:10
  • @RishiRaut, may I ask you to have a look at an `axios` related question here : https://stackoverflow.com/questions/59470085/vue-js-validation-fails-for-file-upload-in-axios-when-multipart-form-data-used ? – Istiaque Ahmed Dec 24 '19 at 14:26
  • 4
    About the comment by @Hiroki 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). – DJ Ramones Feb 26 '21 at 11:18
31

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

xlm
  • 6,854
  • 14
  • 53
  • 55
maris
  • 718
  • 7
  • 8
28

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
        }
    })
}
Emma
  • 27,428
  • 11
  • 44
  • 69
Nathan Blake
  • 400
  • 3
  • 8
  • 10
    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. – Eugene Feb 01 '22 at 08:50
19

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
};
jfk
  • 4,335
  • 34
  • 27
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});
    });
OCornejo
  • 151
  • 1
  • 3
  • 3
    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 lol – Jeff Bluemel May 01 '20 at 20:31
  • 1
    @JeffBluemel `Content-Type` headers are set automagically. You are supposed to have those undefined. – Alan Jereb Sep 06 '21 at 08:35
5

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",
    },
  }
);
vvthai10
  • 51
  • 1
  • 1
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);
}
Yarh
  • 895
  • 7
  • 15
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.

Marc
  • 5,109
  • 2
  • 32
  • 41
-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)
IAmdeGroot
  • 17
  • 2