使用 JavaScript 和 Node.js 循环检索 pdf 发票(Meteor)
Recurly pdf invoice retrieving with JavaScript and Node.js (Meteor)
我们正在开发一个具有 Recurly 集成的应用程序,并尝试使用它的 PDF 发票功能。
该应用程序基于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)
}
并直接保存在服务器上(仅供测试):
var fs = require('fs');
var wstream = fs.createWriteStream('C:/recurly.pdf');
wstream.write(result.content);
wstream.end();
但在这两种情况下,我都得到了无法使用的 pdf 文件。 Acrobat、Foxit reader 和 Chrome 无法打开此文件 — 它已损坏。
你对我错的地方有什么建议吗?也许我需要在保存之前进行一些内容转换或其他任何事情?
已添加
我已将此请求的结果发送给客户端并打印在控制台中(上图)。
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;
}
问题是您正在尝试获取一个二进制文件,该文件包含一个期望编码字符串作为响应的请求。
你最好的选择是告诉请求库它应该期待什么,否则你将不得不手动从 UTF-16
- 或 UTF-8
- 编码的字符串中撬出二进制数据。
客户端和服务器实现之间存在差异。
服务器
服务器实现使用节点的 request
module. You can supply options for it 使用 npmRequestOptions
。
如其文档中所述:
encoding - Encoding to be used on setEncoding of response data. If null, the body is returned as a Buffer. Anything else (including the default value of undefined) will be passed as the encoding parameter to toString() (meaning this is effectively utf8 by default). (Note: if you expect binary data, you should set 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');
舞蹈)。
这可以使用类似下面的代码来实现:
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。
我们正在开发一个具有 Recurly 集成的应用程序,并尝试使用它的 PDF 发票功能。
该应用程序基于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)
}
并直接保存在服务器上(仅供测试):
var fs = require('fs');
var wstream = fs.createWriteStream('C:/recurly.pdf');
wstream.write(result.content);
wstream.end();
但在这两种情况下,我都得到了无法使用的 pdf 文件。 Acrobat、Foxit reader 和 Chrome 无法打开此文件 — 它已损坏。
你对我错的地方有什么建议吗?也许我需要在保存之前进行一些内容转换或其他任何事情?
已添加
我已将此请求的结果发送给客户端并打印在控制台中(上图)。
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;
}
问题是您正在尝试获取一个二进制文件,该文件包含一个期望编码字符串作为响应的请求。
你最好的选择是告诉请求库它应该期待什么,否则你将不得不手动从 UTF-16
- 或 UTF-8
- 编码的字符串中撬出二进制数据。
客户端和服务器实现之间存在差异。
服务器
服务器实现使用节点的 request
module. You can supply options for it 使用 npmRequestOptions
。
如其文档中所述:
encoding - Encoding to be used on setEncoding of response data. If null, the body is returned as a Buffer. Anything else (including the default value of undefined) will be passed as the encoding parameter to toString() (meaning this is effectively utf8 by default). (Note: if you expect binary data, you should set 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');
舞蹈)。
这可以使用类似下面的代码来实现:
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。