【问题标题】:Recurly pdf invoice retrieving with JavaScript and Node.js (Meteor)使用 JavaScript 和 Node.js (Meteor) 定期检索 pdf 发票
【发布时间】:2016-10-29 05:40:42
【问题描述】:

我们正在开发一款集成 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 阅读器和 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;
    }

【问题讨论】:

  • 您是如何获取数据的?你设置了blob responseType 吗?
  • @MasterAM 我使用 recurly docs 来获取数据。 dev.recurly.com/docs/lookup-invoice-details
  • 这不包括 JS API。可以发一些代码吗?
  • @MasterAM 我在帖子中添加了代码示例

标签: javascript node.js pdf meteor recurly


【解决方案1】:

问题是您正在尝试获取一个二进制文件,其中的请求需要一个编码字符串作为响应。

您最好的选择是告诉请求库它应该期待什么,否则您将不得不手动将二进制数据从UTF-16- 或UTF-8- 编码字符串中撬出。

客户端和服务器实现之间存在差异。


服务器

服务器实现使用节点的request 模块。你可以使用npmRequestOptionssupply options for it

如其文档所述:

encoding - 用于响应数据的 setEncoding 的编码。如果为 null,则正文作为缓冲区返回。其他任何内容(包括 undefined 的默认值)都将作为编码参数传递给 toString() (这意味着默认情况下这实际上是 utf8)。 (注意:如果你需要二进制数据,你应该设置 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。

【讨论】:

  • 非常感谢! encoding: null — 是关键,现在我通过服务器正确接收了 pdf。现在我对请求结果使用base64编码return new Buffer(result.content).toString('base64');然后在客户端上用JavaScript打开它window.open("data:application/pdf;base64, " + r);但是据我所知这不是最好的选择吗?我研究了一些将二进制文件从 Node.js 传递到客户端的方法,但还没有找到解决方案。您对如何以最佳方式将 pdf 从客户端传输到服务器有任何想法吗?无论如何,再次感谢您的帮助!
猜你喜欢
  • 1970-01-01
  • 2016-11-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-19
  • 1970-01-01
相关资源
最近更新 更多