请求流程: 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 JavaScript, Web | 38 Comments
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.