【问题标题】:Downloading a PDF from an HTTP POST call从 HTTP POST 调用下载 PDF
【发布时间】:2014-07-30 16:07:35
【问题描述】:

这是我在不使用 JQuery 的情况下尝试完成的(IE 9+、Chrome、FF、Safari):

  1. 使用一些数据对我的 API 端点进行 http POST 调用
  2. 服务器动态生成 PDF 并将 PDF 作为二进制附件返回
  3. 浏览器执行默认下载行为并在不刷新页面的情况下下载 PDF

基本上,我希望获得类似于<a href="test.pdf"> 的行为,但在进行 POST 调用而不是 GET 调用后动态生成的 PDF。

我尝试了很多不同的方法,但它们要么不能跨浏览器工作(例如使用带有 blob URL 的 $window.open()),要么被弹出窗口阻止程序阻止(任何 $window 调用之外的点击范围),或者没有导致 PDF 被自动下载(任何 $http POST 解决方案)。

我终于找到了一个似乎可行的解决方案,它使用 javascript 创建一个表单并提交它。

  var form = document.createElement('form');
  form.setAttribute('method', 'post');
  form.setAttribute('action', myurl);

  var params = {foo: 'bar'};

  for(var key in params) {
      if(params.hasOwnProperty(key)) {
          var hiddenField = document.createElement('input');
          hiddenField.setAttribute('type', 'hidden');
          hiddenField.setAttribute('name', key);
          hiddenField.setAttribute('value', params[key]);
          form.appendChild(hiddenField);
       }
  }

  document.body.appendChild(form);
  form.submit();

这成功完成了上面的 3 个步骤,但现在我遇到了一个新问题。无法确定 PDF 文件何时已成功下载。这使我无法删除表单并向用户显示友好的“请稍候...”消息。还有一个额外的问题是提交表单也会取消任何未完成的 ajax 请求,这不是最佳的。

我可以完全控制服务器和客户端,那么解决此问题的最佳方法是什么?我不想将 PDF 保存在服务器上,因此在这种情况下,传回一个 url 并从客户端执行第二个 GET 请求将不起作用。谢谢!

【问题讨论】:

    标签: forms angularjs http pdf


    【解决方案1】:

    您可以通过应用一些 HTTP 标头使服务器响应表现为下载:

    Content-Type: application/octet-stream
    Content-Disposition: attachment; filename="SOME_NAME.pdf"
    Content-Transfer-Encoding: binary
    

    如果您仅通过 JS 启动下载(而不是让用户单击下载链接),请查看 this question 了解一些注意事项。

    更新:POST 的语法

    更好的更新:带有 iframe 目标的表单解决方案

    您可以通过使表单以 iframe 为目标来检测您的服务器端脚本是否已完成(随后,下载已准备好开始)。我相信这也应该解决取消未完成的 Ajax 调用的问题,但我不确定。这是执行此操作的代码(只需将其粘贴到您的代码示例中 for 循环之后和 document.body.appendChild(form); 之前):

    var frame = document.createElement('iframe');
    frame.setAttribute('id', 'pdfFrame');
    frame.onload = function(){
        document.body.removeChild(form);
        document.body.removeChild(frame);
        alert('Download ready!');
    }
    document.body.appendChild(frame);
    form.setAttribute('target', 'pdfFrame');
    

    您可以用您的代码替换我的alert 以删除“请稍候...”。

    【讨论】:

    • 谢谢。我在服务器上设置这些,这允许表单提交执行下载。链接的问题有点不同,因为他们发出 GET 来填充 iFrame,但我需要发出 POST。
    • 我很高兴标题有助于下载行为。我已经更新了我的答案,以包含一些通过 Angularjs 发出发布请求的示例语法。如果我错过了什么,请告诉我。
    • 如果我只是进行标准的 post 调用,调用会成功,但 PDF 文件不会触发下载行为。响应包含 PDF,但没有其他任何反应。我能够触发下载行为的唯一方法是通过提交表单方法。
    • 对不起,我误解了你之前的评论。我已经用我现在相信您正在寻找的内容再次更新了我的答案。希望对您有所帮助。
    • 感谢您的帮助,不幸的是,Chrome 在通过文件下载定位 iFrame 时不会触发任何事件 :( 请参阅 stackoverflow.com/questions/20572734/…
    猜你喜欢
    • 2012-05-11
    • 1970-01-01
    • 1970-01-01
    • 2019-01-02
    • 1970-01-01
    • 1970-01-01
    • 2019-01-18
    • 1970-01-01
    • 2022-01-11
    相关资源
    最近更新 更多