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

send binary response in node from phantomjs child process

本文关键字:二进制 响应 节点 phantomjs 子进程      更新时间:2023-09-26

我已经创建了一个节点端点来为我的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'不是一个函数(求值'parameters.response.setEncoding("binary")')

我如何以某种方式将二进制文件响应发送到节点函数,以便它可以与我的节点服务器一起发送给用户?

经过一番努力,如果有人偶然发现这篇文章,这里是有效的解决方案。

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

也根据@ArtjomB更新了答案。建议将发送的控制台消息包装在一个唯一的开始和结束字符串中,这样可以降低其他可能的未来输出被误认为是预期呈现的文件对象的风险。

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);
    });
};