-->

Extjs 4 downloading a file through ajax call

2020-03-25 15:17发布

问题:

The problem is very simple: i have to download a file when i submit a form, it's an ajax call when the form is submitted which lets me build a file with the data taken from the form, server side, and then send it as a link to an alert. The fact is that my boss want the file to be downloaded directly and not through a link in an alert. So i had to make sure that the file is available server side through tornado(web):

        self.set_header('Content-Type', 'application/octet-stream')
        self.set_header('Content-Disposition', 'attachment; filename=clients_counter.zip')
        with open("static/clients_counter.zip", 'r') as f:
            while True:
                data = f.read()
                if not data:
                    break
        self.write(data)
        self.finish()

The server side code seems to work fine, but the client side (extjs4.1) is really a nightmare. This is how my ajax call looks like now, and it doesn't work:

Ext.Ajax.request({
method : "GET",
url : 'http://whatever.com/count?client='+client+'&start='+start+'&end='+end,
timeout : 30000,
success :
         function (response) {
    //Ext.Msg.alert(response.responseText);
            desktop.getWindow('count-win').doClose();
            return response;
       }//handler,
     failure : 
     function(response) {
    alert("Wrong request");
    }});

回答1:

After reading on various sources from Ext JS forum and here in stackoverflow, below is the approach I've chosen (using Ext JS version 4.2.1):

downloadFile: function(config){
    config = config || {};
    var url = config.url,
        method = config.method || 'POST',// Either GET or POST. Default is POST.
        params = config.params || {};

    // Create form panel. It contains a basic form that we need for the file download.
    var form = Ext.create('Ext.form.Panel', {
        standardSubmit: true,
        url: url,
        method: method
    });

    // Call the submit to begin the file download.
    form.submit({
        target: '_blank', // Avoids leaving the page. 
        params: params
    });

    // Clean-up the form after 100 milliseconds.
    // Once the submit is called, the browser does not care anymore with the form object.
    Ext.defer(function(){
        form.close();
    }, 100);

}


回答2:

I had a similar problem trying to download an Excel File in an Ajax call I solved it this way:

Make a standard sumbit instead of Ajax.

var form = Ext.create('Ext.form.Panel', { // this wolud be your form 
    standardSubmit: true,         // this is the important part 
    url: '../ObtenerArchivoAdjuntoServlet' 
});

form.submit({
    params: {
       nombreArchivo: nombreArchivo
    }
});

After this you would be able return the desired file.



回答3:

I think you can take a much easier solution. Forget about the ajax, and just get plain old js to open the file for you:

window.open('http://whatever.com/count?client='+client+'&start='+start+'&end='+end)

This will open a new tab and start the download from there.



回答4:

After extracting/reading many posts, I managed to get this simple method to work..

                Ext.create('Ext.form.Panel', {
                    renderTo: Ext.getBody(),
                    standardSubmit: true,
                    url: 'URL'
                }).submit({params: {'PARAM1': param1, 'PARAM2': param2}});


回答5:

I just had to ad to the success function of the ajax request:

window.open('urltothefile.ext')


回答6:

The following code used to download the file using extjs 5 or 6. Add the following code to method and invoke this for button action. This downloads the file directly insteadof opening in new tab.

use an iframe like this:

/**
 * prints the file
 */
printReport: function () {
    var url = 'downloadURL';
    Ext.Ajax.request({
        url: url,
        method: 'GET',
        autoAbort: false,
        success: function(result) {
            if(result.status == 204) {
                Ext.Msg.alert('Empty Report', 'There is no data');
            } else if(result.status == 200) {
                Ext.DomHelper.append(Ext.getBody(), {
                    tag:          'iframe',
                    frameBorder:  0,
                    width:        0,
                    height:       0,
                    css:          'display:none;visibility:hidden;height:0px;',
                    src:          url
                });
            }
        },
        failure: function() {
            //failure here will automatically
            //log the user out as it should
        }
    });
}

Copied the answer from extjs forum

Option:2 If you want to open the file in new tab

    /**
 * open file in tab
 */
openReport: function () {
    var url = 'downloadURL';
    Ext.Ajax.request({
        url: url,
        method: 'GET',
        autoAbort: false,
        success: function(result) {
            if(result.status == 204) {
                Ext.Msg.alert('Empty Report', 'There is no data');
            } else if(result.status == 200) {
                var win = window.open('', '_blank');
                win.location = url;
                win.focus();
            }
        },
        failure: function() {
            //failure here will automatically
            //log the user out as it should
        }
    });
}


回答7:

You cannot use ajax to download file. I've implemented file downloading in extjs which is like ajax. see the blog ajaxlikefiledownload.

FileDownload.downloadFile = function(arguments) {

var url = arguments['url'];
var params = arguments['params'];
var successCallback = arguments['success'];
var failureCallback = arguments['failure'];

var body = Ext.getBody();

var frame = body.createChild({
tag:'iframe',
cls:'x-hidden',
id:'hiddenframe-frame',
name:'iframe'
});

var form = body.createChild({
tag:'form',
cls:'x-hidden',
id:'hiddenform-form',
action: url,
method: 'POST',
target:'iframe'
});


if (params)
{
    for (var paramName in params)
    {

        form.createChild({
            tag:'input',
            cls:'x-hidden',
            id:'hiddenform-'+paramName,
            type: 'text',
            text: params[paramName],
            target:'iframe',
            value: params[paramName],
            name: paramName
            });

    }
}

form.dom.submit();

FileDownload.isFinished(successCallback,failureCallback);

};

FileDownload.isFinished = function(successCallback,failureCallback) {

//Check if file is started downloading
if (Ext.util.Cookies.get('fileDownload') && Ext.util.Cookies.get('fileDownload')=='true' ) {
    //Remove cookie call success callback 
    Ext.util.Cookies.set('fileDownload', null, new Date("January 1, 1970"),application.contextPath+'/');
    Ext.util.Cookies.clear('fileDownload',application.contextPath+'/');
    successCallback();
    return;
} 

//Check for error / IF any error happens then frame will load with content
try {
    if(Ext.getDom('hiddenframe-frame').contentDocument.body.innerHTML.length>0){
        Ext.util.Cookies.set('fileDownload', null, new Date("January 1, 1970"),application.contextPath+'/');
        Ext.util.Cookies.clear('fileDownload',application.contextPath+'/');
        failureCallback();
        //Cleanup
        Ext.getDom('hiddenframe-frame').contentDocument.body.innerHTML = ""; 

        return;
    }
} 
catch (e) {
    console.log(e);
}

console.log('polling..');
// If we are here, it is not loaded. Set things up so we check   the status again in 100 milliseconds
window.setTimeout('FileDownload.isFinished('+successCallback+','+failureCallback+')', 100);

};

Usage :

FileDownload.downloadFile({
  url : url,
  params : params,
  success : function(){
   //Success call back here
  },
  failure : function(){
   //Failure callbak here
  }
});

In the http response you need to add a cookie nammed fileDownload = true