下载PDF文件(Blob)时出现JavaScript错误。

3

我正在使用这种方法从服务器下载pdf文件(laravel 8(api sanctum)+ vue 3)

在vue组件中,我有这个函数来下载文件

const onDownloadDocument = (id) => {           
   axios.post('/api/document/download', {id: id},{
     responseType: 'blob'
   }).then(response => {
     let filename = response.headers['content-disposition'].split('filename=')[1]               
     dLink.value.href = window.URL.createObjectURL(response.data)
     dLink.value.setAttribute('download',filename)
     dLink.value.click()
   }).catch(error => {
      console.log(error)
   })

其中dLink是一个链接引用

const dLink = ref(null)

在模板中:

<a ref="dLink"/>

直到今天这种方法一直奏效...... 在我更新了项目(composer update和npm update)之后

现在当我点击下载文件(调用onDownloadDocument函数)时,会出现错误:

contract.js:1049 Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'responseType')

有什么想法吗?

API后端返回文件blob。

return Storage::download($document->filename);

contract.js:1049是什么?堆栈跟踪将准确告诉您哪一段代码导致了问题。 - miken32
@miken32 这是我在错误捕获中使用的 if 语句 if (error.request.responseType === 'blob' && error.response.data instanceof Blob && error.response.data.type && error.response.data.type.toLowerCase().indexOf('json') !== -1) .... 现在我已经注释掉了所有的 catch 错误代码,只设置了 console.log(error),然后得到了 TypeError: Cannot set properties of null (setting 'href') 的错误提示,它指向这一行代码 dLink.value.href = window.URL.createObjectURL(response.data); - calin24
您确定要在模板中使用dLink吗?您不需要附加到“real”<a>标记,只需动态创建一个即可。 - jeremy castelli
@jeremycastelli 你所说的“on the fly”是什么意思?你能给我举个例子吗? - calin24
代码在评论中不太美观,我会创建一个答案。 - jeremy castelli
2个回答

4
首先,您需要创建一个 Blob 并将响应放入其中。
正如我在评论中所说的那样,您不需要附加到实际的锚标记,只需创建一个元素,将其附加到 body,模拟单击并立即删除它。
const blob = new Blob([response], {type: 'application/pdf'})
if (window.navigator['msSaveOrOpenBlob']) {
    window.navigator['msSaveBlob'](blob, filename)
}
else {
    const elem = window.document.createElement('a')
    elem.href = window.URL.createObjectURL(blob)
    elem.download = filename
    document.body.appendChild(elem)
    elem.click()
    document.body.removeChild(elem)
}

我明白......但这就是我避免使用文档(dom)的原因。在设置中,我有一个引用文档const document = ref({}),对于这个组件来说将其重命名为另一个名称有点复杂。现在出现了错误Cannot read properties of undefined (reading 'appendChild'),因为它试图使用文档模型。有没有办法可以使用文档(dom)而不是文档(模型引用)? - calin24
window.document? - jeremy castelli
哎呀,我忘记了窗口 :-) 现在它可以工作了。 - calin24
太好了!很高兴它能正常工作。 - jeremy castelli
我注意到现在文档已经下载了,但是它显示“文件类型为纯文本文档(text/plain),不支持打开”。看起来这是一个损坏的文件。有什么想法吗? - calin24
固定的 const elem = window.document.createElement('a') elem.href = window.URL.createObjectURL(response.data) elem.setAttribute('download',filename) elem.click() - calin24

1
这对我很有帮助,你需要告诉axios你期望得到一个博客,就可以了:
axios({
  url: 'http://localhost:5000/endpoint?',
  method: 'GET',
  responseType: 'blob', // <= important
}).then((response) => {
  const url = window.URL.createObjectURL(new Blob([response.data]));
  const link = document.createElement('a');
  link.href = url;
  link.setAttribute('download', 'file.pdf');
  document.body.appendChild(link);
  link.click();
});

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接