在快速路由响应中发送 PDF 并强制浏览器下载

Posted

技术标签:

【中文标题】在快速路由响应中发送 PDF 并强制浏览器下载【英文标题】:Send PDF in express route response and force browser download 【发布时间】:2018-05-10 04:57:44 【问题描述】:

背景

我正在快速服务器上生成 PDF 并将其保存到本地目录。在回调中,我试图将 PDF 发送回服务器,以便下载,但它出现在网络选项卡响应中,因为它似乎是二进制文件并且不下载。

示例

编辑我的客户端函数发出服务器请求 此 fetch 调用到达应返回 PDF 的快速端点。特快路线如下,

function setImage() 
  html2canvas(document.querySelector('#chart')).then(canvas => 
    canvas.toBlob(
      function(blob) 
        const url = 'http://localhost:3000/api/v1/pdf';

        fetch(url, 
          method: 'POST',
          headers: 
            'Content-type': 'application/octet-stream',
          ,
          body: blob,
        )
          .then(response => response.json())
          .then(success => console.log(success))
          .catch(error => console.log(error));
      ,
      'image/png',
      1,
    );
    document.body.appendChild(canvas);
  );

// 创建 PDF 并将其保存在服务器上的 filePath

router.post('/', (req, res, next) => 
      pdf.create(html, options).toFile(filePath, err => 

            if (err) 
              return console.log(err);
            
            const stat = fs.statSync('./downloads/report.pdf');
            res.contentType('application/pdf');
            res.setHeader('Content-Length', stat.size);
            res.setHeader('Content-Type', 'application/pdf');
            res.setHeader('Content-Disposition', 'attachment; filename=report.pdf');
        // *Should force download the file to the browser*
            res.download('../downloads/report.pdf', 'report.pdf', function(e) 
              if (e) 
                // Handle error, but keep in mind the response may be partially-sent
                // so check res.headersSent
               else 
                // It worked, do something else.
              
            );
          );
    );

编辑我也在服务器上试过这个,它在浏览器中显示响应,但不会下载文件。

router.post('/', (req, res, next) => 
  const img = req.body;
  const filepath = 'uploads/chart.png';
  fs.writeFile(filepath, img, err => 
    if (err) 
      throw err;
    
    console.log('The file was succesfully saved!');
  );

  const html = tmpl.replace('chart', `file://$require.resolve('../uploads/chart.png')`);
  const options =  format: 'Letter' ;
  const fileName = 'report.pdf';
  const filePath = './downloads/report.pdf';

  pdf.create(html, options).toFile(filePath, err => 
    if (err) 
      return console.log(err);
    
    const stat = fs.statSync('./downloads/report.pdf');
    res.setHeader('Content-Description', 'File Transfer');
    res.setHeader('Content-Length', stat.size);
    res.setHeader('Content-type', 'application/octet-stream');
    res.setHeader('Content-type', 'application/pdf');
    res.setHeader('Content-Type', 'application/force-download');
    res.setHeader('Content-disposition', 'attachment;filename=report.pdf');

    res.sendFile('/downloads/report.pdf');
  );

浏览器输出示例

问题

Express 4 中强制浏览器下载 PDF 的正确方法是什么?

【问题讨论】:

我测试了您的代码,它似乎在我的示例中运行良好。它更多地与浏览器选择如何处理这种 mime 类型有关,“下载”的链接放在哪里?你能分享那个代码吗? 【参考方案1】:

我现在看到了您的问题,fetch 使用 AJAX 在后台发出请求,响应转到您的代码,然后您捕获它并将其作为 JSON 写入屏幕。 为了打开文件对话框并下载文件,您需要有一个指向与<a href=....> 相同位置的链接,或者您可以尝试此处建议的内容 How can I download a file using window.fetch?

【讨论】:

以上是关于在快速路由响应中发送 PDF 并强制浏览器下载的主要内容,如果未能解决你的问题,请参考以下文章

python Django下载HTTP响应类,强制在浏览器中下载。

.htaccess 在 Safari 中强制 PDF 下载

PHP如何强制下载文件

下载使用GET使用POST创建的文件

如何在移动浏览器上使用 PHP 强制下载文件?

在浏览器中输入网站域名并按下回车的详细过程