1

I'm trying to get - after some promises have been executed - a CSV result back together with a status reponse having details.

The response does get me the data for the CSV but I cannot seem to get the browser to download this data into a CSV file.

router.post('/getSalesOrders', function (request, response) {
    var data = request.body;
    salesOrderActions.retrieveSalesOrders(data) //
        .then(function (result) {
            response.setHeader('Content-disposition', 'attachment; filename=testing.csv');
            response.set('Content-Type', 'text/csv');
            response.json(result[0].message).send(result[0].file);
        })
        .catch(function (err) {
            console.log(err);
            if (err.statusCode) {
                response.json(err);
            }
            else {
                var error = output.getCriticalErrorResult(c.titles.SERVICE_CRITICAL_ERROR, c.messages.UNKNOWN_ERROR, err.message);
                response.json(error);
            }
        });
});

My result object gets created in the salesOrderActions:

I am here using npm package json2csv

var fields = ['id',.....];
var csv = csvParser({ data: unmatchedLines, fields: fields });

return {
     file: csv,
     message:
         output.getSuccessResult(
             titles.SALES_ORDER_SUCCESS_RETRIEVAL,
             salesDataForModel.identifier
         )
}

My response to the browser is as follows: enter image description here enter image description here

So my message isn't sent it seems and I do get the CSV data but not as a file to download. How can I manage that?

As a sidenote maybe, my front-end is React

EDIT

Response with octed headers:

enter image description here enter image description here

Tikkes
  • 4,219
  • 4
  • 30
  • 57

3 Answers3

2

Try:

  • sending Content-Type before Content-Disposition
  • quoting the filename: filename="testing.csv"

Also HTTP headers are case insensitive, so it should not make a difference, but you should write Content-Disposition (capital D).

response.set('Content-Type', 'text/csv');

response.setHeader('Content-Disposition', 'attachment; filename="testing.csv"');

If this does not work you can change the Content-Type to application/octet-stream

This always forces the browser to download the data sent from the server.

filippo
  • 2,716
  • 1
  • 15
  • 18
  • for Content-disposition, there is no problem I use it in a project with disposition with a small 'd'. But for application/octed-stream you are right – Ediruth Jul 20 '16 at 11:29
  • Still get the same result. The response contains the csv data but no download is starten on this. – Tikkes Jul 20 '16 at 11:34
  • even if you use application/octet-stream as Content-type? response.set('Content-Type', 'application/octet-stream'); – filippo Jul 20 '16 at 11:44
  • Yes, even then. I do get the csv data in the response though, but no download starts. I'll update the question with what exactly I get as a result – Tikkes Jul 20 '16 at 11:45
  • Sorry, just reread your post. You are making the request via Ajax? That's problem I think. Change it to be a simple form posting data to a url. In this way it should work... Can you post the code that makes the call to the server and the headers sent? – filippo Jul 20 '16 at 12:03
1

Try this code:

router.post('/getSalesOrders', function (request, response) {
    var data = request.body;
    var fs = require('fs');

   salesOrderActions.retrieveSalesOrders(data) //
    .then(function (result) {
       //**********
        var file = "testing.csv";
        response.setHeader('Content-disposition', 'attachment; filename=testing.csv');
        response.set('Content-Type', 'text/csv');
        var filestream = fs.createReadStream(file);
        filestream.pipe(res);
       //*********
    })
    .catch(function (err) {
        console.log(err);
        if (err.statusCode) {
            response.json(err);
        }
        else {
            var error = output.getCriticalErrorResult(c.titles.SERVICE_CRITICAL_ERROR, c.messages.UNKNOWN_ERROR, err.message);
            response.json(error);
        }
    });
});
Ediruth
  • 168
  • 1
  • 7
1

So actually it turns out it is because I'm doing an Ajax request which doesn't - by default - prompt the browser to download any files.

What I did in the end:

router.post('/getSalesOrders', function (request, response) {
    var data = request.body;
    salesOrderActions.retrieveSalesOrders(data)
        .then(function (result) {
            response.json(result);
        })
        .catch(function (err) {
            //...
        });
});

And then in my front-end, when receiving the result:

salesOrderService.retrieveSalesOrderData()
.then(function (result) {
    self.convertAndDownloadCsv(result.unmatchedLines);
});

convertAndDownloadCsv: function (data) {
    if (data && data.length > 0) {
        var csvData = csvProcessor({ //using csv2json node js package
            data: data,
            quotes: '',
            del: ';'
        });
        var filename = "unmatchedLinesFromSalesOrders.csv";
        var blob = new Blob([csvData], { type: 'text/csv;charset=utf-8;' });
        if (navigator.msSaveBlob) { // IE 10+
            navigator.msSaveBlob(blob, filename);
        } else {
            var link = document.createElement("a");
            if (link.download !== undefined) { // feature detection
                // Browsers that support HTML5 download attribute
                var url = URL.createObjectURL(blob);
                link.setAttribute("href", url);
                link.setAttribute("download", filename);
                link.style.visibility = 'hidden';
                document.body.appendChild(link);
                link.click();
                document.body.removeChild(link);
            }
        }
    }
}

More info can be found here

Community
  • 1
  • 1
Tikkes
  • 4,219
  • 4
  • 30
  • 57