简体   繁体   中英

Download file via jquery ajax post

I am trying to export my web page data and download it as excel file. but the download does not start even the response return succeed.

$.ajax({
      type: "POST",
      url: _url,
      contentType: 'multipart/form-data;boundary=SzB12x',
      data: json,
    });

The responseText something like this:

PK J;F?xl/theme/theme1.xml YOo 6 ,[r n;v i #- kJH: oC{0 X7 2 mZ d u@ (٦b:M {| ^ 0t@ *"w$ !0I [ ՚n i ' iH g , | J ?!? hRh h ?r& L ߶S v@ ? # ׮ ?" } Жt% hR t" + ? u{ނ 0K oy 9OT WywkAͯ F 6* [ U

I think its the file but I cant download it!!

Any help please?

Thanks!

I faced the same issue and successfully solved it. My use-case is this.

  • Post JSON data to server and receive an excel file.
  • That excel file is created on the fly and returned as a response to client.

Code:

$("#my-button").on("click", function() {
    // Data to post
    data = {
        ids: [1, 2, 3, 4, 5]
    };

    // Use XMLHttpRequest instead of Jquery $ajax
    xhttp = new XMLHttpRequest();
    xhttp.onreadystatechange = function() {
        var a;
        if (xhttp.readyState === 4 && xhttp.status === 200) {
            // Trick for making downloadable link
            a = document.createElement('a');
            a.href = window.URL.createObjectURL(xhttp.response);
            // Give filename you wish to download
            a.download = "test-file.xls";
            a.style.display = 'none';
            document.body.appendChild(a);
            a.click();
        }
    };
    // Post data to URL which handles post request
    xhttp.open("POST", excelDownloadUrl);
    xhttp.setRequestHeader("Content-Type", "application/json");
    // You should set responseType as blob for binary responses
    xhttp.responseType = 'blob';
    xhttp.send(JSON.stringify(data));
});

The above snippet is just doing following

  • Posting an array as JSON to the server using XMLHttpRequest
  • After fetching content as a blob(binary), we are creating a downloadable URL and attaching it to invisible "a" link then clicking it.

Here we need to carefully set few things at the server side. I set few headers in Python Django HttpResponse. You need to set them accordingly if you are use other programming languages.

# In python django code
response = HttpResponse(file_content, content_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")

Since I download xls(excel) here, I adjusted contentType to above one. You need to set it according to your file type.

Try to use a hidden form to submit the request.

When a user submits an HTML form, all the data entered into the form by the user is sent as either a GET or POST request to the URL specified in the “ACTION” attribute of FORM.

 <FORM action="http://www.labnol.org/sendmail.php" method="post">
 ...form contents...
 </FORM>

In the above example, an HTTP POST request is issued to the sendmail.php script on form submission. You can add target=”_blank” to the FORM tag to process the request in a new window.

However, if you would like to submit a FORM on the page in the background without directing the browser to another page (document.location.href changes on form submit), you have two options:

Option #1. You can either create an invisible IFRAME inside your HTML page and set that as a target for the Original FORM. This will submit the form but without reloading the parent window.

<FORM action="http://example.com/script.php" 
           method="POST" target="hidden-form">
 ...form contents... 
 </FORM>
<IFRAME style="display:none" name="hidden-form"></IFRAME> 

Option #2: There's another method that allows you create custom payloads before submitting the form. Unlike the IFRAME based form submission, the following code makes a standard form submit request and thus your browser location will change and the current page will get added to the browser history. Credit: Rakesh Pai.

submitFORM('http://example.com/script.php', 'POST',
    {'name':'digital+inspiration', 'age':'100', 'sex','M'});

function submitFORM(path, params, method) {
    method = method || "post"; 

    var form = document.createElement("form");
    form.setAttribute("method", method);
    form.setAttribute("action", path);

    //Move the submit function to another variable
    //so that it doesn't get overwritten.
    form._submit_function_ = form.submit;

    for(var key in params) {
        if(params.hasOwnProperty(key)) {
            var hiddenField = document.createElement("input");
            hiddenField.setAttribute("type", "hidden");
            hiddenField.setAttribute("name", key);
            hiddenField.setAttribute("value", params[key]);

            form.appendChild(hiddenField);
         }
    }

    document.body.appendChild(form);
    form._submit_function_();
}

In this link you can find the way to create hidden form and submit it.

enjoy!!

The approach here is directly lifted from https://gist.github.com/DavidMah/3533415 .

This approach uses <form> and appends the data with a key. This approach works if the server is already expecting the data as an attribute of the request body, as opposed to being the request body itself. If the data to be uploaded is an object, you could iterate over that object's keys. If the data to be uploaded is an array, either modify the server route or [add idea here].

In browser

// Takes a URL, param name, and data string
// Sends to the server... The server can respond with binary data to download
jQuery.download = function(url, key, data) {
    // Build a form
    var form = $('<form></form>').attr('action', url).attr('method', 'post');
    // Add the one key/value
    form.append($("<input></input>").attr('type', 'hidden').attr('name', key).attr('value', data));
    //send request
    form.appendTo('body').submit().remove();
};

On server

# A Tidbit of sinatra code to respond
# Assume 'url' is a set variable
# Assume 'key' is the key of the value used in the javascript

post url do
  data = params[:key]
  puts request.body.read
  headers['Content-Type'] = "application/octet-stream"

  body(data)
end

Example

$.download('/path/resource/', 'data', JSON.stringify(data))

If you just want to download a file, you don't need to use ajax to do it. Actually, you cannot download file using ajax.
You can still do it by making a hyperlink <a href="your_link">Export</a> request to a server page that responses content-type is application/vnd.ms-excel and content-disposition is attachment .

$.ajax({
    type: "POST",
    contentType: "application/json; charset=utf-8",
    url: yoururlpath,
    success: function (response) {
        var file = fileName+".xlsx";
        window.location = "someFilePath?file=" + file;
    }
});

You can achieve this using an iFrame as well. A sample function:

// append the data to URL
var requestData = {
    param1 : "value1",
    param2 : "value2",
}

// call the function
downloadFile(<your_URL>, requestData);

function downloadFile(requestURL, data) {
    // "transData" is just a user defined variable to encapsulate "downloadIFrame". It can be named anything as required.
    var downloadIFrame = window.transData.downloadIFrame = window.transData.downloadIFrame || $("#downloadFileiFrame");
    downloadIFrame.attr("src", requestURL + $.param(requestData));
}

// define the iFrame in your HTML and hide it.
<iframe id="downloadFileiFrame" style="display:none;"></iframe>"

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM