从 phantomjs 子进程在节点中发送二进制响应

send binary response in node from phantomjs child process

我已经创建了一个节点端点来为我的 svg 图表创建栅格化版本。

app.post('/dxexport', function(req, res){
    node2Phantom.createPhantomProcess(req,res);
});

我的节点到幻影功能使用 spawn 到 运行 phantomjs

var spawn = require('child_process').spawn;
exports.createPhantomProcess = function(req,res){

    var userRequest = JSON.stringify(req.body);
    var bin = "node_modules/.bin/phantomjs"
    var args = ['./dxexport/exporter-server.js', userRequest, res];
    var cspr = spawn(bin, args);


    cspr.stdout.on('data', function (data) {
        var buff = new Buffer(data);
        res.send(data);
    });

    cspr.stderr.on('data', function (data) {
        data += '';
        console.log(data.replace("\n", "\nstderr: "));
    });

    cspr.on('exit', function (code) {
        console.log('child process exited with code ' + code);
        process.exit(code);
    });

};

渲染完成并成功创建文件后,我在 phantomjs:

中调用 renderCompleted 函数
var renderCompleted = function (parameters) {
    var exportFile = fileSystem.open(parameters.exportFileName, "rb"),
        exportFileContent = exportFile.read();
    parameters.response.statusCode = 200;
    parameters.response.headers = {
        "Access-Control-Allow-Origin": parameters.url,
        "Content-Type": contentTypes[parameters.format],
        "Content-Disposition": "attachment; fileName=" + parameters.fileName + "." + parameters.format,
        "Content-Length": exportFileContent.length
    };
    parameters.response.setEncoding("binary");
    parameters.response.write(exportFileContent);

    /////// somehow send exportFileContent as node res object for download \\\\
    exportFile.close();
    parameters.format !== "svg" && fileSystem.remove(parameters.exportFileName);
    for (var i = 0; i < parameters.filesPath.length; i++)
        fileSystem.remove(parameters.filesPath[i]);
    parameters.filesPath = [];
    parameters.response.close()
};

此响应是从 nodejs 传递的,但显然此代码正在调用 phantomjs 方法,因此我收到类似

的错误

TypeError: 'undefined' is not a function (evaluating 'parameters.response.setEncoding("binary")')

我怎样才能以某种方式将二进制文件响应发送到节点函数,以便它可以通过我的节点服务器发送给用户?

感谢任何帮助。

好的,如果有人无意中发现了这个问题,那么经过一番努力,这里是可行的解决方案 post。

正如 Artjom B. 提到的,我发现最简单的方法是将可视化的渲染和文件创建委托给 phantomjs。然后通过控制台发送与这些操作相关的所有参数。

Also updated the answer based on @ArtjomB.'s advice to wrap the console message sent in a unique beginning and end string so the risk of the other possible future outputs being mistaken for the intended rendered file object is mitigated.

var renderCompleted = function (parameters) {
    console.log("STRTORNDRD" + JSON.stringify(parameters) + "ENDORNDRD");
};

然后它会被 stdout 接收并像这样使用:

exports.exportVisual = function (req, res) {

    var userRequest = JSON.stringify(req.body);
    var bin = "node_modules/.bin/phantomjs"
    var args = ['./dxexport/exporter-server.js', userRequest, res];
    var cspr = spawn(bin, args);
    var contentTypes = {
        pdf: "application/pdf",
        svg: "image/svg+xml",
        png: "image/png"
    };


    cspr.stdout.on('data', function (data) {

        var buff = new Buffer(data).toString('utf8');
        var strData = buff.match(new RegExp("STRTORNDRD" + "(.*)" + "ENDORNDRD"));

        if (strData) {

            var parameters = JSON.parse(strData[1]);

            var img = fs.readFileSync(parameters.exportFileName);
            var headers = {
                "Access-Control-Allow-Origin": parameters.url,
                "Content-Type": contentTypes[parameters.format],
                "Content-Disposition": "attachment; fileName=" + parameters.fileName + "." + parameters.format,
                "Content-Length": img.length
            };

            res.writeHead(200, headers);
            res.end(img, 'binary');

            // delete files after done
            if (parameters.format != "svg") {
                fs.unlink(parameters.exportFileName);
            }

            for (var i = 0; i < parameters.filesPath.length; i++)
                fs.unlink(parameters.filesPath[i]);

            // done. kill it
            cspr.kill('SIGINT');

        }

    });

    cspr.stderr.on('data', function (data) {
        data += '';
        console.log(data.replace("\n", "\nstderr: "));
    });

    cspr.on('exit', function (code) {
        console.log('child process exited with code ' + code);
        process.exit(code);
    });

};