73

I am trying to send file with XMLHttpRequest with this code.

var url= "http://localhost:80/....";
$(document).ready(function(){
    document.getElementById('upload').addEventListener('change', function(e) {
        var file = this.files[0];
        var xhr = new XMLHttpRequest();
        xhr.file = file; // not necessary if you create scopes like this
        xhr.addEventListener('progress', function(e) {
            var done = e.position || e.loaded, total = e.totalSize || e.total;
            console.log('xhr progress: ' + (Math.floor(done/total*1000)/10) + '%');
        }, false);
        if ( xhr.upload ) {
            xhr.upload.onprogress = function(e) {
                var done = e.position || e.loaded, total = e.totalSize || e.total;
                console.log('xhr.upload progress: ' + done + ' / ' + total + ' = ' + (Math.floor(done/total*1000)/10) + '%');
            };
        }
        xhr.onreadystatechange = function(e) {
            if ( 4 == this.readyState ) {
                console.log(['xhr upload complete', e]);
            }
        };
        xhr.open('post', url, true);
        xhr.setRequestHeader("Content-Type","multipart/form-data");
        xhr.send(file);
    }, false);
});

I get this error: T

The request was rejected because no multipart boundary was found.

What am I doing wrong?

Willi Mentzel
  • 27,862
  • 20
  • 113
  • 121
Sedat Başar
  • 3,740
  • 3
  • 25
  • 28

2 Answers2

116
  1. There is no such thing as xhr.file = file;; the file object is not supposed to be attached this way.
  2. xhr.send(file) doesn't send the file. You have to use the FormData object to wrap the file into a multipart/form-data post data object:

    var formData = new FormData();
    formData.append("thefile", file);
    xhr.send(formData);
    

After that, the file can be access in $_FILES['thefile'] (if you are using PHP).

Remember, MDC and Mozilla Hack demos are your best friends.

EDIT: The (2) above was incorrect. It does send the file, but it would send it as raw post data. That means you would have to parse it yourself on the server (and it's often not possible, depend on server configuration). Read how to get raw post data in PHP here.

timdream
  • 5,914
  • 5
  • 21
  • 24
  • 5
    xhr.send(file) is based on XHR2 which is a new version of the XMLHttpRequest object only avalable in some browsers. – nkassis Apr 20 '12 at 19:19
  • 1
    @nkassis yeah, but it would send the file itself as the post body, instead of constructing a multipart postdata for server to parse. – timdream Apr 22 '12 at 18:19
  • How come jquery can do it and pure javascript cannot? – John Smith Oct 18 '12 at 22:48
  • How do you send more then one file? Can you just keep appending? – gmustudent Mar 06 '13 at 09:47
  • 3
    This method requires at least IE10 or Android 3.0. – andreszs Aug 05 '14 at 15:14
  • Why are you saying that the `(2)` way to send a file is incorrect? I don't understand. It will automatically construct a multipart postdata and add `multipart/form-data...` headers as long as you send a `FormData` object. – Rick Aug 14 '19 at 15:17
  • 1
    @gmustudent Yes, keep appending. MDN has an excellent article about this topic [Using FormData Objects](https://developer.mozilla.org/en-US/docs/Web/API/FormData/Using_FormData_Objects) – Rick Aug 14 '19 at 15:19
  • Note that using FormData() with xhr doesn't works with Safari on IOS, you have to use fetch – spartanz51 Jan 13 '20 at 23:40
  • 1
    `Failed to execute 'append' on 'FormData': parameter 2 is not of type 'Blob'` – Abhi Jan 23 '20 at 13:42
0

A more extended answer:

let formData = new FormData();
formData.append("fileName", audioBlob);

$.ajax({
    "url": "https://myserver.com/upload",
    "method": "POST",
    "headers": {
        "API-Key": "myApiKey",
    },
    "async":        true,
    "crossDomain":  true,
    "processData":  false,
    "contentType":  false,
    "mimeType":     "multipart/form-data",
    "data":         formData
}).done(function(response){

    console.log(response);

});