Thursday, 20 April 2017

Running Export Module Under iisnode

I have set up iisnode and installed the highcharts-export-server in the directory I am hoping to be the server endpoint via:

1) I have copied an existing directory under C:\Program Files\iisnode\www to a new directory under the C:\Program Files\iisnode\www path in Windows (where the sample iisnode pages exist).

2) I have opened a command prompt in this new directory (as administrator) and run the following:

npm init (leaving all options as default/empty
npm install --save highcharts-export-server (and responded to the questions asked)

3) I have set up my endpoint file as hcexport.js and it contains:

var http = require('http');
var qs = require('querystring');
const exporter = require('highcharts-export-server');


http.createServer(function (request, res) {
    if (request.method == 'POST') {
        var body = '';
        request.on('data', function (data) {
            body += data;
            // 1e6 === 1 * Math.pow(10, 6) === 1 * 1000000 ~~~ 1MB
            if (body.length > 1e6) {
                // FLOOD ATTACK OR FAULTY CLIENT, NUKE REQUEST
                request.connection.destroy();
            }
        });
        request.on('end', function () {
            var POST = qs.parse(body);
            var extype = POST.type;

            // use POST
            console.log(POST);

            exporter.initPool();

            exporter.export(POST, function (err, exres) {
                //The export result is now in exres.
                //If the output is not PDF or SVG, it will be base64 encoded (res.data).
                //If the output is a PDF or SVG, it will contain a filename (res.filename).
                console.log(exres);

                if (extype == 'image/png' || extype == 'image/jpeg') {
                    res.setHeader('Content-disposition', 'attachment; filename=' + exres.filename);
                    res.setHeader('Content-type', extype);
                    res.write(exres.filename);
                    res.end();
                }

                if (extype == 'image/svg+xml') {
                    res.setHeader('Content-disposition', 'attachment; filename=' + exres.filename);
                    res.setHeader('Content-type', extype);
                    res.write(exres.filename);
                    res.end();
                }

                if (extype == 'application/pdf') {
                    res.setHeader('Content-disposition', 'attachment; filename=' + exres.filename);
                    res.setHeader('Content-type', extype);
                    res.write(exres.filename);
                    res.end();
                }

                //Kill the pool when we're done with it, and exit the application
                exporter.killPool();
                process.exit(1);
            });
        });
    }


}).listen(process.env.PORT);

I then created a sample chart (stock chart) that is representative of some of our data and chart options. I use the built-in chart export logic when a user clicks on a button to export the chart (we do not use the built-in button menu). This code looks like:

var chart = $('#' + chartid).highcharts();
var navigatorData = chart.get("highcharts-navigator-series").options.data;
var chartSeries = chart.userOptions.series;

chart.exportChart({
    filename: 'test',
    type: exportType,
    scale: 1
}, {
    title: {
        text: graphHeader,
        margin: marginSize
    },
    navigator: {
        series: {
            data: navigatorData
        }
    },
    legend: {
        y: -6
    },
    subtitle: {
        y: 3,
        text: graphFooter
    },
    chart: {
        spacingBottom: 35,
        shadow: false,
        height: 1.1 * chart.chartHeight,
        width: 800
    },
    series: chartSeries
});

When I click our button to export the attempt fails instantly with an error returned to the page that held the chart. In iisnode they provide a logging mechanism and this shows the contents of my POST request:

{ '------WebKitFormBoundaryaes0yytBA1i6RUkH\r\nContent-Disposition: form-data; name': '"filename"\r\n\r\ntest\r\n------WebKitFormBoundaryaes0yytBA1i6RUkH\r\nContent-Disposition: form-data; name="type"\r\n\r\nimage/png\r\n------WebKitFormBoundaryaes0yytBA1i6RUkH\r\nContent-Disposition: form-data; name="width"\r\n\r\n0\r\n------WebKitFormBoundaryaes0yytBA1i6RUkH\r\nContent-Disposition: form-data; name="scale"\r\n\r\n1\r\n------WebKitFormBoundaryaes0yytBA1i6RUkH\r\nContent-Disposition: form-data; name="svg"\r\n\r\nhttp://www.w3.org/2000/svg" width="800" height="550" viewBox="0 0 800 550">Created with Highstock 5.0.10....

And then a nice useful error message:

Thu Apr 20 2017 08:28:40 GMT-0400 (Eastern Daylight Time) [error] no input specified { contents of the POST }

How can I get the export server to return the chart image? What have I missed here?

I did another test using what should be sent in as a manual POST request following the instructions here. In this case I have the same node module code but my export looks like:

var exportRequest = {
    svg: theChartSVG,
    scale: 1,
    filename: 'test',
    type: exportType,
    async: true
};

var exportUrl = 'http://myurl/node/exporter/';
$.post(exportUrl, exportRequest, function (data) {
    var url = exportUrl + data;
    console.log(url);
});

This is interesting for several reasons. One is that the code in the export module states that:

            //The export result is now in exres.
            //If the output is not PDF or SVG, it will be base64 encoded (res.data).
            //If the output is a PDF or SVG, it will contain a filename (res.filename).

If I send up just the exres.data I get nothing. But if I send up exres.filename as the return and then build a URL string as you see on the success code set as var url = exportUrl + data; I get a valid url with a filename.extension that I can click on and open and see the chart. But, I am unable to force a download of the image. The other interesting aspect of this is that the exres.filename sent back is not the input filename I sent to the export server. It is undefinedchart.png for example. If I request an SVG for export I get no exres.filename sent up to the requester page - but I can got to the assumed URL and actually view the SVG image. What is happening?



via wergeld

No comments:

Post a Comment