Get excel file (.xlsx) from server response in ajax
Asked Answered
B

4

12

I have got a problem with getting excel file and opening download window in the browser after getting a response (in success ajax method) with that file. I have got appropriate Content-Type and Content-Disposition headers, I tried using Blob in js and I couldn't achieve what I want - simple file downloading.
I accomplished few versions of my ajax, one of them is below. I developed ajax which returns excel file which I couldn't open properly because it's corrupted (despite .xlsx extension).

Maybe the problem is with inappropriate data type used in Blob constructor?

I tried using "xhr.response" instead of "data" from success method arguments but it doesn't work too. I checked Response Headers in Developer Tools in Chrome and they are set properly.
The important thing - all the excel workbooks created on the server side is correct because it worked in the previous version when data was sent in URL, not in ajax post.

Controller method in Java/Spring server side below:

response.reset();
response.setContentType("application/vnd.ms-excel");
response.addHeader("Content-Disposition","attachment;filename=\"" + className + " " +  title + ".xlsx\"");
    try (ServletOutputStream output = response.getOutputStream()){
        workbook.write(output);
        output.flush();
    } catch (Exception e) {
        throw new RuntimeException(e);
    }

My Ajax to download file and open download window:

$.ajax({
    url: myUrl,
    type: 'POST',
    data: myData,
    success: function(data, status, xhr) {
        var contentType = 'application/vnd.ms-excel';

        var filename = "";
        var disposition = xhr.getResponseHeader('Content-Disposition');
        if (disposition && disposition.indexOf('attachment') !== -1) {
            var filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/;
            var matches = filenameRegex.exec(disposition);
            if (matches != null && matches[1]) filename = matches[1].replace(/['"]/g, '');
        }
        console.log("FILENAME: " + filename);

        try {
            var blob = new Blob([data], { type: contentType });

            var downloadUrl = URL.createObjectURL(blob);
            var a = document.createElement("a");
            a.href = downloadUrl;
            a.download = filename;
            document.body.appendChild(a);
            a.click();

        } catch (exc) {
            console.log("Save Blob method failed with the following exception.");
            console.log(exc);
        }
Basilio answered 6/11, 2017 at 10:25 Comment(0)
B
24

It looks like JQuery have got some problem with dealing with the binary data from the response. I used simply XMLHttpRequest and I add all data to the URL.

var request = new XMLHttpRequest();
request.open('POST', url, true);
request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
request.responseType = 'blob';

request.onload = function(e) {
    if (this.status === 200) {
        var blob = this.response;
        if(window.navigator.msSaveOrOpenBlob) {
            window.navigator.msSaveBlob(blob, fileName);
        }
        else{
            var downloadLink = window.document.createElement('a');
            var contentTypeHeader = request.getResponseHeader("Content-Type");
            downloadLink.href = window.URL.createObjectURL(new Blob([blob], { type: contentTypeHeader }));
            downloadLink.download = fileName;
            document.body.appendChild(downloadLink);
            downloadLink.click();
            document.body.removeChild(downloadLink);
           }
       }
   };
   request.send();
Basilio answered 9/11, 2017 at 9:17 Comment(5)
Oh my god thank you soo much for this answer. You are the best!Leathaleather
fileName on line 16 has not been defined. Where do you define that?Truly
@Möoz It's set up before. But in this case it doesn't matter because it could be anything like "My_File.xlsx"Basilio
i am able to download the file but when i open it it says "Sorry,we couldn't find C:\mypath[object Object],[object Object],....[object Ob.xls. Is it possible it was moved, renamed or deleted?" Also is there anyway to change the name of the file during download?Roddie
This worked for me too after trying most of the jQuery-Ajax method options.Hesson
C
6

After so many searches for getting an excel file from web API with Unicode content. Finally, this code works for me :

$.ajax({
                type: 'GET',
                cache: false,
                url: "https://localhost:44320/WeatherForecast",
              
                xhrFields: {
                    // make sure the response knows we're expecting a binary type in return.
                    // this is important, without it the excel file is marked corrupted.
                    responseType: 'arraybuffer'
                }
            })
                .done(function (data, status, xmlHeaderRequest) {
                    var downloadLink = document.createElement('a');
                    var blob = new Blob([data],
                        {
                            type: xmlHeaderRequest.getResponseHeader('Content-Type')
                        });
                    var url = window.URL || window.webkitURL;
                    var downloadUrl = url.createObjectURL(blob);
                    var fileName = '';

                  

                    if (typeof window.navigator.msSaveBlob !== 'undefined') {
                        window.navigator.msSaveBlob(blob, fileName);
                    } else {
                        if (fileName) {
                            if (typeof downloadLink.download === 'undefined') {
                                window.location = downloadUrl;
                            } else {
                                downloadLink.href = downloadUrl;
                                downloadLink.download = fileName;
                                document.body.appendChild(downloadLink);
                                downloadLink.click();
                            }
                        } else {
                            window.location = downloadUrl;
                        }

                        setTimeout(function () {
                            url.revokeObjectURL(downloadUrl);
                        },
                            100);
                    }
                });

Corkage answered 15/7, 2021 at 18:10 Comment(0)
O
1

We were having absolutely the same trouble recently. For us it started to work when we add responseType: 'arraybuffer' to the ajax parameters. And it's better to use lib https://github.com/eligrey/FileSaver.js/ instead of manual clicking on the link because this tool revokes memory as well.

Orit answered 8/11, 2017 at 18:56 Comment(1)
I have tried with responseType: 'arraybuffer' but it failed because of the inappropriate responseType which was text probably. But I resolved this problem with directly creating XMLHttpRequest. Working code in the comment below.Basilio
D
0

in my case this sinpcode work correctly

$('.btnExportToExcel').click(async (e) => {
    e.preventDefault();
    const info = JSON.parse(e.currentTarget.dataset.info);
    let action = 1;
   

    try {
        const data = {
        idCampagna: info.idCampagna,
        fileName: info.fileName,
       };
         this.ShowSpinner("Downloading");

        // this.HideSpinner();

        $.ajax({
            type: 'GET',
            cache: false,
            url: "ExportToExcel",
            data: data,
            xhrFields: {
                // make sure the response knows we're expecting a binary type in return.
                // this is important, without it the excel file is marked corrupted.
                responseType: 'arraybuffer'
            }
        })
            .done(function (data, status, xmlHeaderRequest) {
                var downloadLink = document.createElement('a');
                var blob = new Blob([data],
                    {
                        type: xmlHeaderRequest.getResponseHeader('Content-Type')
                    });
                var url = window.URL || window.webkitURL;
                var downloadUrl = url.createObjectURL(blob);
                var fileName = '' +'.xls';



                if (typeof window.navigator.msSaveBlob !== 'undefined') {
                    window.navigator.msSaveBlob(blob, fileName);
                } else {
                    if (fileName) {
                        if (typeof downloadLink.download === 'undefined') {
                            window.location = downloadUrl;
                        } else {
                            downloadLink.href = downloadUrl;
                            downloadLink.download = fileName;
                            document.body.appendChild(downloadLink);
                            downloadLink.click();
                        }
                    } else {
                        window.location = downloadUrl;
                    }

                    setTimeout(function () {
                        url.revokeObjectURL(downloadUrl);
                    },
                        100);
                }
            });
        this.HideSpinner();
    } catch (error) {
        console.log(error);
    }
});
Definite answered 2/11, 2023 at 8:58 Comment(1)
As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.Giraffe

© 2022 - 2024 — McMap. All rights reserved.