【问题标题】:Pull PDF from Amazon S3 and render directly in Browser from buffer/stream从 Amazon S3 提取 PDF 并从缓冲区/流直接在浏览器中呈现
【发布时间】:2018-05-26 17:57:02
【问题描述】:

我有一个要求,即 PDF 不保存在本地服务器上,而是私下存储在 Amazon S3 存储桶上。但是根据特定请求,我需要检索 PDF 并直接在用户的浏览器中呈现它,而不是在 Web 服务器上下载它。

我能够在 node.js 中提取流并使用 PDF 数据进行响应。当我在 Chrome 开发工具中检查响应数据时,它看起来像 PDF 数据,我什至可以阅读文档中的文本。

let params = {Bucket: process.env.S3STORAGE, Key: req.query.fileName};
res.attachment(req.query.fileName);
s3.getObject(params).createReadStream().pipe(res);

我已经尝试了多种方法来正确渲染它。它要么显示一个空白的 PDF,要么显示令人毛骨悚然的 PDF 数据。

我正在使用 vue2 模板,并尝试在引导模式中弹出 PDF。在这次尝试中,我得到了一个空白 PDF:

<object :data="pdfStream" type="application/pdf" width="800px" :height="browserHeight"></object>


this.pdfStream = response.bodyText;

我看到一些回答说 base64 对其进行了编码,但仍然无法正常工作。

// server side
let params = {Bucket: process.env.S3STORAGE, Key: req.query.fileName};
s3.getObject(params).createReadStream().pipe(strs('binary', 'base64')).pipe(res);

然后

//client side
 let objbuilder = '';
        objbuilder += ('<object width="100%" height="100%" data="data:application/pdf;base64,');
        objbuilder += (response.bodyText);
        objbuilder += ('" type="application/pdf" class="internal">');
        objbuilder += ('<embed src="data:application/pdf;base64,');
        objbuilder += (response.bodyText);
        objbuilder += ('" type="application/pdf"  />');
        objbuilder += ('</object>');
        this.pdfStream = objbuilder;

当然,我错过了一些简单的东西,或者犯了一个愚蠢的错误,但不确定是什么。我一直只提供实际文件,但在这个特定实例中,目标是直接将数据呈现到浏览器中,而不生成位于 S3 存储中的 PDF 副本。

更新

Jason 的回答为我指明了正确的方向,我相信我现在走在正确的轨道上。但是它会引发我不确定的错误。

我的第一次尝试是这样的:

// returning a base64 encoded PDF from Amazon to the client
let params = {Bucket: process.env.S3STORAGE, Key: req.query.fileName};
s3.getObject(params).createReadStream().pipe(strs('binary', 'base64')).pipe(res);

然后在客户端Vue组件中:

//import PDFJS from 'pdfjs-dist';
export default {
  {components: PDFJS},
  ...
  ...

  ...
  viewDocument(fileName, documentName) {

      this.$http.get('/fetchDocument', {
        params: {
          fileName: fileName
        }
      })
      .then(response => {

         PDFJS.getDocument(response.bodyText).then(function (pdfDocument) {

          console.log('Number of pages: ' + pdfDocument.numPages);

        });
      });

    },

它会回击这个错误:

app.js:58668 GET http://192.168.3.14:3000/dist/app.worker.js net::ERR_ABORTED
app.js:55073 Warning: Setting up fake worker.
app.js:104 GET http://192.168.3.14:3000/0.js net::ERR_ABORTED
app.js:99 Uncaught (in promise) Error: Loading chunk 0 failed.
    at HTMLScriptElement.onScriptComplete (app.js:99)

pdfjs-dist 库中没有 app.worker.js0.js

然后...如果我从节点返回没有 base64 的原始方式,它返回的原始 PDF 流开始如下:

%PDF-1.2
%����
3 0 obj
<< 
/Lineariz

我得到一个完全不同的错误

Uncaught (in promise) TypeError: Failed to construct 'URL': Invalid URL

最后,我在node返回的base64编码数据上尝试了here中的base64Uint8Array函数,这导致了我刚刚收到的app.worker.js和0.js 404错误。

pdfjs-dist 包没有那些 js 文件,所以不确定到底发生了什么。

有什么想法吗?

【问题讨论】:

  • 您是否尝试过手动设置标题,就像这里一样? stackoverflow.com/a/10047018/5734311
  • 我还没有,但我今晚回家后会的。但是,响应标头当前显示: Content-Disposition:attachment; filename="1513046394445.pdf" 内容类型:应用程序/pdf
  • 这里的关键是你需要从 web 文件夹中拉取查看器组件:import {PDFJS as PDFJSViewer} from 'pdfjs-dist/web/pdf_viewer'; 然后从那里去
  • @Jason 谢谢。如果我不能让它工作,我会继续尝试并提出一个新问题。
  • 你得到这个工作了吗@Nathan。如果是的话,你能把它贴在这里吗?

标签: javascript node.js amazon-s3


【解决方案1】:

您需要使用渲染器将 PDF 数据渲染到浏览器中。 Mozilla 的PDF.JS project 就是这样一个项目。既然用的是vue,可以看下这个例子使用:https://github.com/shershen08/vue2-pdfjs-viewer

浏览器已经内置了 PDF 阅读器,但不是在 JS 应用程序的上下文中。这就是 PDF.JS 项目发挥作用的地方。

【讨论】:

  • 感谢您的回答!如果您有任何见解,我会为我的问题添加更新。
猜你喜欢
  • 1970-01-01
  • 2013-09-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-20
  • 2011-07-16
  • 2011-03-01
  • 2013-07-09
相关资源
最近更新 更多