0

I am programming an embedded Device in C with a webserver. One Task is to download files from this devices. I want to Download serveral files at once, so i created an ajax-request, which using POST-Request and a bunch of filenames to return a zip-file (i create these zip-file on my own on the device). Everything works fine, but the dialog save as appears after the whole zip-file was transmitted.

At server-side the device is sending the 200 OK-, Content-Type: application/octet-stream- and Content-Disposition: attachment; filename="testzip.zip"-headers.

At client-side i using this javascript-code(got this from stackoverlfow: Handle file download from ajax post):

function downloadFiles(filenames) {
    var xhr = new XMLHttpRequest();
    xhr.open('POST', /file-save/, true);
    xhr.responseType = 'arraybuffer';
    xhr.onload = function () {
        if (this.status === 200) {
            var filename = "test.zip";
            var type = xhr.getResponseHeader('Content-Type');

            var blob = new Blob([this.response], { type: type });
            var URL = window.URL || window.webkitURL;
            var downloadUrl = URL.createObjectURL(blob);

            // use HTML5 a[download] attribute to specify filename
            var a = document.createElement("a");

            a.href = downloadUrl;
            a.download = filename;
            document.body.appendChild(a);
            a.click();


            setTimeout(function () { URL.revokeObjectURL(downloadUrl); }, 100); // cleanup

        }
    };
    xhr.send(filenames);
}

The if-statement if (this.status === 200) is reached, when the whole file is transmitted. If the size of the file is small, there is not a problem, because the user isn't recognizing the lack of time. But is the file about 50MB the user can't see any download although the file is downloading. In my opinion the reason is a.click(), because the click-method imitades the begin of the download.

Is there sombody who can help me out with a solution or some hints? By the way, jquery isn't an option!.

Thanks for any help

EDIT: my goal is to download a file like on every webpage with large files, where i get a dialog with the location to save and i can see the download-progress.

SOLUTION(Hint from Herr Derb):

function downloadFiles(filenames) {
    var xhr = new XMLHttpRequest();
    xhr.open('POST', /file_save/, true);

    xhr.onload = function () {
        if (this.status === 200) {
            var mydisp = xhr.getResponseHeader('Content-Disposition');

            var save_response = xhr.responseText;
            var var_json_format = JSON.parse(save_response);

            /* check for errors */
            if(var_json_format["error"]) {
                return;
            } else {
                status = _.findWhere(var_json_format["link"], {id : 'status'}).value;
                download_id = _.findWhere(var_json_format["link"], {id : 'download_id'}).value;
            }

            if(status != "active") {
                return;
            }

            var filename = "test.zip";
            var downloadUrl = "/file_save/" + download_id;

            var a = document.createElement("a");

            a.href = downloadUrl;
            a.download = filename;
            document.body.appendChild(a);
            a.click();
            document.body.removeChild(a);

            setTimeout(function () { URL.revokeObjectURL(downloadUrl); }, 100); // cleanup

        }
    };

    xhr.send(filenames);
    return;
}
Community
  • 1
  • 1
Chris
  • 315
  • 1
  • 4
  • 17
  • You could use Ajax as defined in the question you have linked. And in ajax instead of `success:` you can use `complete:` which will call when the ajax request completed. – Ahmed Khan Aug 29 '16 at 11:07
  • but am i right this is a jquery-solution? – Chris Aug 29 '16 at 11:19
  • yes according to my knowledge you are right – Ahmed Khan Aug 29 '16 at 11:22
  • ok, but i can't use jquery – Chris Aug 29 '16 at 11:24
  • why you just need to add jquery CDN in the header – Ahmed Khan Aug 29 '16 at 11:25
  • you are right, but i develope a device, which has no internet-connection and the memory is to small to store jquery. I like to use a solution without jquery. – Chris Aug 29 '16 at 11:30
  • It's absolutely logical that the "save as" dialogue appears only in the end. The code downloads your zip file, then runs the `status==200`. At this time you got all the data already in the cache of your client. the whole server client transmission is done. The last part that the code does (with part with the `a` tag) is to create a temporary local js file with the downloaded data, which is called a blob. This gets linked to a dummy hyper link which gets clicked. Therefore a Save as dialogue appears. – Herr Derb Aug 29 '16 at 11:33
  • Ohh then try https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/onreadystatechange this might help you out – Ahmed Khan Aug 29 '16 at 11:34
  • @HerrDerb: yes, i understood, i hope you can provide me a solution to prompt the save as dialog a the beginnt. All my attempts failed. – Chris Aug 29 '16 at 11:37
  • @AhmedKhan: thanks, i also tried several things with the `readyState`, but it didn't workt out either. I will try it again. – Chris Aug 29 '16 at 11:40

1 Answers1

0

Your first request should only create the zip file on your server and return a link to reach it. After you received that link on the client site, simply execute it. This way, everything will happen as you desire, as it will be a regular file download. And ss soon the download is finished, your free to delete the file again.

Herr Derb
  • 4,977
  • 5
  • 34
  • 62
  • ok, i will give a try. But I have to create the zip-file dynamically, because i got not enough storage to create a big file. Maybe i can develope a workaround. – Chris Aug 29 '16 at 11:45
  • Well the easiest way is that you just show a loader until the ajax call is completed. the point is, that you never will know the size of the download during this. – Herr Derb Aug 29 '16 at 11:57