web开发-前端(angular)download, server(nodejs)端用python和相关插件生成report,

请求流程: web --> nodejs --> python(generate excel) --> Mongodb

 

#f5cd68

Python 2.7.5
[GCC 4.8.5 20150623 (Red Hat 4.8.5-16)]

// install below 5 plugin
$ sudo python setup.py install
mongo-python-driver-master/
functools32-3.2.3-2
vcversioner-2.16.0.0
jsonschema-2.6.0
XlsxWriter-0.8.5

 

python -c "import pymongo; print(pymongo.version); print(pymongo.has_c())"
3.6.0.dev0
False

which python
python --version
// scl can switch the python version
source scl_source enable rh-python36

 

前端:Angular

后端:nodejs(v8.11),python(Python 2.7.5)

 

----------------------------------

具体示例如下:

前端:

1. angular发起异步请求到nodejs,在http请求中提供相关参数,比如

// page Component
    public downloadExcelFile() {
		let parameter = {
			pyName: 'pyName',
			parameterForPy: {
						date: '',
						Name: '',
						outPutPath: ''
					}
		}

        this.downloadServ.downloadExcelByPy(parameter).subscribe(data => {
            
            if (window.navigator.msSaveOrOpenBlob) {
                navigator.msSaveBlob(data, fileName);
            } else {
                var link = document.createElement('a');
                link.href = window.URL.createObjectURL(data);
                link.download = fileName;
                link.click();
                window.URL.revokeObjectURL(link.href);
            }
        });
    }



// downloadServ Service
public downloadExcelByPy(parameter) {
    let body = {
        pyName: parameter.pyName,
        parameterForPy: parameter.parameterForPy
    }

	let headers = new HttpHeaders();

	return this._http.post('/test/downloadExcelByPy', body, { headers: headers, observe: 'response', responseType: "blob" }).map(response => {
				if (response["status"] == 400) {
					console.error("400 error");
				} else if (response["status"] == 200) {
					let contentType = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
					let blob = new Blob([(<any>response).body], { type: contentType });
					return blob;
				}
			});
}

 

后端:

在nodejs端,调用python相关程序,生成report,并放置到指定的目录下,并用stream流读取返回到resp里

此处,在nodejs端用spawn方式调用python的程序,并且nodejs和python程序约定好输入和输出参数即可

比如,retData[0] === 91 && retData[1] === 48即为约定参数,代表是否成功生成report

const fs = require('fs');
const path = require('path');
var spawn = require('child_process').spawn;

module.exports.downloadExcelByPy = function(req, res) {

    const outPutPath = '.../reportGeneratorPath/';
    let py = spawn('python', ['pyfile_root_path/pyreportGenerator.py']);
    let parameterForPy = req.body.parameterForPy;
    parameterForPy.outPutPath = outPutPath;

    let pythonReturn;
    let pythonErr;
    let isSuccess = false;

    logger.info('userName', 'downloadExcelByPy', 'Start...');

    py.stdin.write(JSON.stringify(parameterForPy));

    py.stdin.end();

    py.stdout.on('data', function(retData) {

        logger.info('userName', 'downloadExcelByPy > stdout data', 'retData: ' + retData.toString());

        if (retData[0] === 91 && retData[1] === 48) {
            pythonReturn = JSON.parse("{\"ret\":" + retData.toString().replace(/\'/g, "\"") + "}").ret;
            isSuccess = true;
        }
    });

    py.stdout.on('end', function() {

        if (isSuccess) {

            logger.info('userName', 'downloadExcelByPy > stdout end', 'isSuccess:' + isSuccess + '; pythonReturn[1]: ' + pythonReturn[1]);
            let fileName = pythonReturn[1];
            let filePath = path.join(outPutPath, fileName);
            let stats = fs.statSync(filePath);
        
            logger.info('userName', 'getFile', 'Start...');
        
            if (stats.isFile()) {
                res.set({
                    'Content-Type': 'application/octet-stream',
                    'Content-Disposition': 'attachment; filename=' + fileName,
                    'Content-Length': stats.size
                });
        
                logger.info('userName', 'getFile > isFile', 'End, Ready to response...');

                const srcReadStream = fs.createReadStream(filePath);

                res.status(200);
                srcReadStream.pipe(res);

                srcReadStream.on('error', function (err) {
                    logger.error(...);
                    srcReadStream.destroy();
                });
                srcReadStream.on('close', function () {
                    logger.info('userName', 'downloadExcelByPy', 'End.');
                    srcReadStream.destroy();
                });

                // fs.createReadStream(filePath).pipe(res);
            } else {
        
                logger.info('userName', 'getFile > is NOT File', 'End, 404 to response...');
                res.end(404);
            }
        } else {
            let err = {};
            err.messageType = _RMSCONSTS.TYPE_ERROR_PY_GEN_FAILED;
            err.language = _RMSCONSTS.MULTI_LANGUAGE_JP;
            logger.info('userName', 'downloadExcelByPy', 'End, 404 to response...' + err);
            res.end(404);
        }
    });

    py.stderr.on('data', function(errData) {

        logger.info('userName', 'downloadExcelByPy > stderr data', 'errData: ' + errData.toString());
        pythonErr = errData;
    });
};

----------------------------------

上面的示例,类似于这篇文章的download,是一个道理

https://blog.jayway.com/2017/07/13/open-pdf-downloaded-api-javascript/

How to open a pdf downloaded from an API with JavaScript

July 13, 2017 by Anders Poulsen in JavaScriptWeb | 38 Comments

Anders Poulsen

On my most recent assignment I was faced with the challenge of downloading a pdf file from an API and displaying it in the browser.

Normally, the API would provide a json-object with a link to the pdf, which can then be used to open a new browser tab/window and the browser or platform takes care of the rest.

In this case however the API was designed for native mobile apps and required the presence of a custom ‘api-key’ http-header, which made it impossible to just provide the url to the browser.

To solve this it was necessary to download the file to memory with an XHR request and then get the browser to open or download it with whatever plugin/UI it normally uses for pdf file.

For the XHR request we use the Fetch API with the whatwg-fetch polyfill. In essence the Fetch API fetch() method returns a response, from which a blob can be created. This blob object can be use to create an objectURL, which can then be used as href in a link.

showFile(blob){
  // It is necessary to create a new blob object with mime-type explicitly set
  // otherwise only Chrome works like it should
  var newBlob = new Blob([blob], {type: "application/pdf"})

  // IE doesn't allow using a blob object directly as link href
  // instead it is necessary to use msSaveOrOpenBlob
  if (window.navigator && window.navigator.msSaveOrOpenBlob) {
    window.navigator.msSaveOrOpenBlob(newBlob);
    return;
  } 

  // For other browsers: 
  // Create a link pointing to the ObjectURL containing the blob.
  const data = window.URL.createObjectURL(newBlob);
  var link = document.createElement('a');
  link.href = data;
  link.download="file.pdf";
  link.click();
  setTimeout(function(){
    // For Firefox it is necessary to delay revoking the ObjectURL
    window.URL.revokeObjectURL(data);
  , 100}
}

fetch([url to fetch], {[options setting custom http-headers]})
.then(r => r.blob())
.then(showFile)

This solution works on Chrome, Safari, Firefox, Opera, IE11 and Edge.

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值