【问题标题】:Problem downloading a PDF blob in JavaScript在 JavaScript 中下载 PDF Blob 时出现问题
【发布时间】:2019-03-19 21:55:36
【问题描述】:

我创建了一个函数,该函数采用 blobfileName,它应该下载实现如下的 blob:

const blobToBase64 = (blob, callback) => {
  const reader = new FileReader();
  reader.onloadend = () => {
    const base64 = reader.result;
    console.log({ base64 });
    callback(base64);
  };
  reader.readAsDataURL(blob);
};

const downloadFile = (blob, fileName) => () => {
  const link = document.createElement('a');
  blobToBase64(blob, (base64) => {
    link.href = base64;
    link.download = fileName;
    link.click();
  });
};


downloadFile(myBlob, myFileName);

为了尝试调试,我创建了一个console.log 以注销由reader.result 创建的base64 的值。

base64 的值为 data:application/octet-stream;base64,Mzc4MDY4...

我的 PDF 文件已下载,但已损坏。我在文件下载实现中做错了什么?

如果有任何其他细节可能对此有所帮助,请告诉我?我 100% 确定 blob 本身不是损坏的文件。

【问题讨论】:

  • 文件类型应该是application/pdf,而不是application/octet-stream
  • application/pdf 替换application/octet-stream 并不能解决问题。
  • 那么你的 blob 可能只是无效的。你确定不是吗?
  • 我很确定它不是无效的,正在调查它:/
  • @BarryMichaelDoyle 你的问题得到解决了吗?

标签: javascript file download base64 blob


【解决方案1】:

我无法确定您的代码为什么不起作用,但我可以确定您的所作所为充其量是无用的。

不要将 Blob 转换为 dataURI,在 99%* 的情况下,您想要使用此 dataURI 执行的操作可以直接使用原始 Blob 和 blobURI 完成。

*剩下的 1% 是当您需要创建包含二进制数据的独立文档时,这种情况会发生,但并不经常发生。

在这里,你想要做的(设置一个锚点指向你的 Blob 的数据)可以直接用 Blob 完成:只需通过调用 @ 创建一个 blobURI(它只是一个指向内存中数据的指针) 987654321@.

const downloadFile = (blob, fileName) => {
  const link = document.createElement('a');
  // create a blobURI pointing to our Blob
  link.href = URL.createObjectURL(blob);
  link.download = fileName;
  // some browser needs the anchor to be in the doc
  document.body.append(link);
  link.click();
  link.remove();
  // in case the Blob uses a lot of memory
  setTimeout(() => URL.revokeObjectURL(link.href), 7000);
};


downloadFile(new Blob(['random data']), "myfile.txt");

【讨论】:

  • 无论出于何种原因,iOS 对这个实现真的很怀疑。有人说这是关于合成点击事件,所以我在页面上创建了一个 ,其中 href 是对象 URL。这适用于 iOS 上的 Safari + Firefox,但 Chrome 没有。有人遇到过这个问题吗?
  • @3stacks,这可能是因为调用了 revokeObjectURL 的焦点,并为此使用了更好的解决方案进行了编辑,您能否确认它是否适合您(我手头没有 iOS 设备)。
  • @Kaiido 感谢您如此迅速地回复队友。我添加了 revokeObjectURL 并得到了一些不同的行为。它实际上适用于 iOS Safari,但 iOS Firefox 只是在同一个窗口中打开 blob,而 iOS Chrome 什么也不做。我尝试了几种不同的方法,例如在挂载时生成对象 URL,然后将其作为 href 添加到适用于 safari 和 firefox 的 DOM,但 chrome 存在问题。编辑:老实说,我认为这可能只是 iOS 很古怪。桌面 macOS 和 android 浏览器工作正常。
  • ...不幸的是,正如我所说,我没有 iOS 设备来测试它...这应该符合标准。 Safari for iOS 在 v13 中添加了支持,我找不到任何与 FF 或 Chrome for iOS 相关的内容。很抱歉,我们可能需要第三个人来帮忙。 Ps:刚看了Eligrey的FileSaver和they are using an ugly isChromeIOS UA sniffing切换到href=dataURI...
【解决方案2】:

我尝试使用 Fetch API 从服务器下载 PDF 文件,该文件提供 octet-stream 内容作为响应。所以,如果你检查响应,你会得到像%PDF-1.4这样的字符

解决方法如下:

function download(pdfUrl) {
        fetch(pdfUrl).then(resp => resp.arrayBuffer()).then(resp => {

            // set the blog type to final pdf
            const file = new Blob([resp], {type: 'application/pdf'});

            // process to auto download it
            const fileURL = URL.createObjectURL(file);
            const link = document.createElement('a');
            link.href = fileURL;
            link.download = "FileName" + new Date() + ".pdf";
            link.click();
        });
    }

您可以使用相同的方法并在创建 blob 之前解码八位字节流的内容。

【讨论】:

  • 对我来说你的代码没问题,但我没有使用 createObjectURL() 两次,只是一次(见const fileURL = ...link.href = ... 行)。我没有尝试过上面的双重 createObjectURL 版本,所以我不能说它是否有效
  • @DanieleCruciani 我想你是对的。我做了两次,同时使代码更具可读性。更新了代码。谢谢。
  • 当它尝试从服务器下载时,您可能会遇到 CORS 错误
猜你喜欢
  • 1970-01-01
  • 2022-01-22
  • 1970-01-01
  • 2017-09-29
  • 2020-11-21
  • 2012-10-20
  • 1970-01-01
  • 2015-09-14
  • 2013-11-04
相关资源
最近更新 更多