用JavaScript和Node.js(meteor)检索返回的pdf发票
我们正在开发一个与Recurly集成的应用程序,并试图使用它的PDF发票function。
该应用程序基于Node.js(meteor平台)。
它从二进制文件接收Recurly的正确答案:
但是我不能正确保存它。 我已经尝试了两种方法:在浏览器的客户端打印:
var file = window.URL.createObjectURL(new Blob([r.content], {type: "application/pdf"})); var a = document.createElement("a"); a.href = file; a.download = "invoicePDF"; document.body.appendChild(a); a.click(); window.onfocus = function () { document.body.removeChild(a) }
并将其直接保存在服务器上(仅供testing):
var fs = require('fs'); var wstream = fs.createWriteStream('C:/recurly.pdf'); wstream.write(result.content); wstream.end();
但在这两种情况下,我已经结束了非工作的PDF文件。 Acrobat,Foxit阅读器和Chrome不能打开这个文件 – 已经损坏了。
你有什么build议,我错了吗? 也许我需要一些内容转换之前保存或其他任何东西?
添加
这个请求的结果我已经发送到客户端,并在控制台中打印(上图)。
try { result = HTTP.call( 'GET', 'https://' + Meteor.settings.recurly.SUBDOMAIN + '.recurly.com/v2/invoices/' + invoiceId, { headers: { Authorization: "Basic " + (new Buffer(Meteor.settings.recurly.API_KEY)).toString('base64'), Accept: 'application/pdf' } } ); } catch (err) { result = e; }
问题是你正在试图获得一个二进制文件的请求,预计编码string作为响应。
你最好的select是告诉请求库它应该期望什么,否则你将不得不手工从UTF-16
或UTF-8
编码string中撬出二进制数据。
客户端和服务器实现是有区别的。
服务器
服务器实现使用节点的request
模块。 您可以使用npmRequestOptions
提供选项 。
正如其文件所述:
编码 – 编码用于setEncoding响应数据。 如果为null,则正文返回为Buffer。 其他任何东西(包括未定义的默认值)都将作为编码parameter passing给toString()(这意味着默认情况下是有效的)。 ( 注意:如果你期望二进制数据,你应该设置encoding:null。 )
所以,在服务器上,你可以做一些事情:
try { result = HTTP.call( 'GET', 'https://' + Meteor.settings.recurly.SUBDOMAIN + '.recurly.com/v2/invoices/' + invoiceId, { headers: { Authorization: "Basic " + (new Buffer(Meteor.settings.recurly.API_KEY)).toString('base64'), Accept: 'application/pdf' }, npmRequestOptions: { encoding: null // will cause the result to be stored in a binary Buffer } } ); // will write the file in binary mode fs.writeFile(outFileName, res.content, 'binary'); } catch (err) { result = e; }
客户
客户端实现使用XHR。
为了处理二进制响应,您需要将XHR的responseType
更改为(最好) 'blob'
。
不幸的是,我没有办法在Meteor当前实现的HTTP包中获取二进制blob,因为它预期响应具有responseText
。
您可以直接使用XMLHttpRequest
对象,但是您可能需要添加一些包装代码来支持垂死的浏览器(IE6,我正在看你!) – 通常new ActiveXObject('Microsoft.XMLHttp');
dance)。
这可以通过使用类似下面的代码来实现:
var xhr = new XMLHttpRequest(); xhr.open('GET', url, true); xhr.setRequestHeader('Authorization', ...); xhr.responseType = 'blob'; // this is key xhr.onload = function(e) { if (this.status == 200) { // this.response is a Blob. If you are sure that it is of the // correct content-type, you can use it to construct the URL directly let blob = new Blob([this.response], {type: 'application/pdf'}); let url = URL.createObjectURL(blob); let a = document.createElement("a"); a.href = url; a.download = "invoice.pdf"; document.body.appendChild(a); ... } }; xhr.send();
它发送一个XHR,将响应编码成一个二进制Blob,并用正确的数据生成一个ObjectURL。