所以这里是我的设置的架构概述:
现在在Spring API中,我有一个API调用来动态生成一个zip文件。此调用返回一个分块的二进制流。
我需要做的是在Node / Express中捕获此流并将其传递回AngularJS前端。
用户旅程是用户检查要导出的项目列表,单击按钮以确认导出,并向节点发出http请求。 Node然后向Spring发送请求,Spring返回流,并将结果发送回AngularJs。
不需要任何关于我们应该如何使用Node / Express或Spring的讲座 - 架构将会发生变化,现在这是很多遗留代码。
对Spring的当前快递请求:
exports.zipRequest = function(path, postBody, onResult) {
var options = {
host: host,
port: port,
path: springContext + path,
method: 'POST',
encoding: 'binary',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/zip'
}
};
var req = http.request(options, function (res){
var output = '';
res.setEncoding('binary');
res.on('data', function (chunk) {
output += chunk;
});
res.on('end', function () {
onResult(res.statusCode, output);
});
}).on('error', function(e) {
console.log("Got error: " + e.message);
req.end();
});
req.write(postBody.toString());
req.end();
};
当前节点API:
exports.exportSessions = function(req, res) {
var dataset = req.user.dataset;
var id = req.params.id;
var arr = JSON.stringify(req.body);
var today = new Date();
var filename = today.toISOString();
filename = filename.replaceAll("-","_");
filename = filename.replaceAll(":","_");
filename = filename.replace(".","_");
var path = '/Export/dataset/'+dataset+'/exportZip/';
api.zipRequest(path, arr, function(statusCode, result) {
if(statusCode != 200) {
console.log(statusCode);
console.log(result);
res.send(statusCode, "Problem from backend API");
} else {
if (result != null || typeof result != 'undefined') {
res.type('application/zip')
res.attachment(filename+'.zip');
res.send(result, 'binary');
} else {
res.send(statusCode, "Undefined Result" + result);
}
}
});
};
想要弄清楚如何让客户端浏览器保存返回的文件 - 因为我可以看到二进制字符串很好,并且我设置了所有必需的标头。我已经尝试了从在Express中创建缓冲区并将其返回到Node API响应中的res.write()
并且似乎没有任何工作。
编辑:
所以我设法使用以下内容将Express拉回到客户端:
var req = http.request(options, function (res){
var today = new Date();
var filename = today.toISOString();
filename = filename.replaceAll("-","_");
filename = filename.replaceAll(":","_");
filename = filename.replace(".","_");
res.setEncoding('binary');
res.pipe(onResult);
};
并在Node中:
exports.exportSessions = function(req, res) {
var dataset = req.user.dataset;
var id = req.params.id;
var arr = JSON.stringify(req.body);
var today = new Date();
var filename = today.toISOString();
filename = filename.replaceAll("-","_");
filename = filename.replaceAll(":","_");
filename = filename.replace(".","_");
var path = '/Export/dataset/'+dataset+'/exportZip/';
res.type('application/zip')
res.attachment(filename+'.zip');
return api.zipRequest(path, arr, res);
}
我可以在开发者控制台中看到整个文件流到客户端(浏览器),响应头如下:
access-control-allow-headers:Origin, Content-Type, X-Auth-Token
access-control-allow-methods:POST, GET
access-control-allow-origin:*
cache-control:private, no-cache, must-revalidate
Connection:keep-alive
content-disposition:attachment; filename="2016_11_16T09_34_50_976Z.zip"
content-type:application/zip
Date:Wed, 16 Nov 2016 09:34:51 GMT
expires:-1
Transfer-Encoding:chunked
X-Powered-By:Express
虽然仍然没有骰子获得保存提示。
答案 0 :(得分:1)
所以我终于明白了。希望这给任何想要保留初始请求的人提供了一个相当深入的答案,并从次要中传回响应。
我通过使用npm request模块解决了这个问题,并将我的Node API调用从POST修改为GET:
var request = require('request');
exports.exportSessions = function(req, res, next) {
var dataset = req.user.dataset;
var arr = decodeURIComponent(req.query.ids);
var path = '/Export/dataset/'+dataset+'/exportZip/';
console.log('Exporting Data '+arr);
var options = {
method: 'POST',
uri: 'http://' + api.host + ':' + api.port + api.springContext + path,
headers: {
'Content-Type': 'application/json',
'Accept': 'application/zip'
},
json: true,
body: JSON.parse(arr)
};
request.post(options).pipe(res)
}
并将我的Angular请求更改为只使用获取URL打开一个新窗口:
$scope.exportData = function() {
var ids = $scope.sessions.selected.map(function(ses){
return ses.id;
});
var pars = encodeURIComponent(JSON.stringify(ids));
window.open('/api/sessions/export/sessions?ids='+pars+'&access_token='+Auth.getToken(), '_blank');
}
这将使用NodeJS API路径简短地打开一个新窗口,然后调用Spring / Hibernate API并将响应作为对原始请求的响应进行管道传输。
Node API的最后一行使用request
向Spring / Hibernate服务器发出POST请求,并通过初始res
对象传回响应。希望这有助于其他任何想要将远程二进制文件传递回客户端的人。