Vue + Laravel:如何正确下载PDF文件?

时间:2018-06-07 08:38:52

标签: javascript php laravel pdf vue.js

情况:

前端:Vue。后端:Laravel。

在网络应用程序中,我需要让用户下载某些pdf文件:

  • 我需要Laravel获取该文件并将其作为API GET请求的响应返回。
  • 然后在我的Vue网络应用程序中,我需要获取文件并下载它。

代码:

API:

$file = public_path() . "/path/test.pdf";

$headers = [
    'Content-Type' => 'application/pdf',
];
return response()->download($file, 'test.pdf', $headers);

网络应用

downloadFile() {
  this.$http.get(this.apiPath + '/download_pdf')
    .then(response => {
      let blob = new Blob([response.data], { type: 'application/pdf' })
      let link = document.createElement('a')
      link.href = window.URL.createObjectURL(blob)
      link.download = 'test.pdf'
      link.click()
    })
}

观察:

使用此代码我设法下载pdf文件。问题是pdf是空白的。

不知何故数据被破坏了(不是这个特殊的pdf文件的问题,我尝试过几个pdf文件 - 结果相同)

从服务器回复:

来自服务器的响应本身很好:

enter image description here

PDF:

问题可能出在pdf文件中。它肯定看起来已损坏的数据。这是response.data

看起来如何的摘录

enter image description here

问题:

如何使用Laravel为Web应用程序正确下载pdf文件和Vue?

谢谢!

4 个答案:

答案 0 :(得分:13)

<强> SOLUTION:

应归功于@Sagar指出我正确的方向。

上面的代码是正确的。缺少的是将responseType添加为arraybuffer

我对答案中的那些????感到害怕,这误导了我。 这些问号是正常的,因为pdf是一个二进制数据,并且应由适当的读者阅读。

ARRAYBUFFER:

而arraybuffer正好用于保存二进制数据。

这是mozilla网站的定义:

  

ArrayBuffer对象用于表示通用的固定长度   原始二进制数据缓冲区你不能直接操纵内容   一个ArrayBuffer;相反,您创建一个类型化的数组对象或   一个DataView对象,它表示特定格式的缓冲区,   并用它来读取和写入缓冲区的内容。

ResponseType字符串表示响应的类型。通过告诉它的arraybuffer,它会相应地处理数据。

只需添加responseType,我就可以正确下载pdf文件。

代码:

这是更正的Vue代码(与以前完全相同,但添加了responseType):

downloadFile() {
  this.$http.get(this.appApiPath + '/testpdf', {responseType: 'arraybuffer'})
    .then(response => {
      let blob = new Blob([response.data], { type: 'application/pdf' })
      let link = document.createElement('a')
      link.href = window.URL.createObjectURL(blob)
      link.download = 'test.pdf'
      link.click()
    })
}

修改

这是一个考虑到其他浏览器行为的更完整的解决方案:

downloadContract(booking) {
  this.$http.get(this.appApiPath + '/download_contract/' + booking.id, {responseType: 'arraybuffer'})
    .then(response => {
      this.downloadFile(response, 'customFilename')
    }, response => {
      console.warn('error from download_contract')
      console.log(response)
      // Manage errors
      }
    })
},

downloadFile(response, filename) {
  // It is necessary to create a new blob object with mime-type explicitly set
  // otherwise only Chrome works like it should
  var newBlob = new Blob([response.body], {type: 'application/pdf'})

  // IE doesn't allow using a blob object directly as link href
  // instead it is necessary to use msSaveOrOpenBlob
  if (window.navigator && window.navigator.msSaveOrOpenBlob) {
    window.navigator.msSaveOrOpenBlob(newBlob)
    return
  }

  // For other browsers:
  // Create a link pointing to the ObjectURL containing the blob.
  const data = window.URL.createObjectURL(newBlob)
  var link = document.createElement('a')
  link.href = data
  link.download = filename + '.pdf'
  link.click()
  setTimeout(function () {
    // For Firefox it is necessary to delay revoking the ObjectURL
    window.URL.revokeObjectURL(data)
  }, 100)
},

答案 1 :(得分:5)

您将无法从LaravelVue进行下载,因为两者都在我假设的不同端口上运行。

即使你尝试过这样的事情。

public function getDownload()
    {
        //PDF file is stored under project/public/download/info.pdf
        $file= public_path(). "/download/info.pdf";

        $headers = [
              'Content-Type' => 'application/pdf',
           ];

    return response()->download($file, 'filename.pdf', $headers);
    }

Laravel端口发送标头时无效,尝试使用Vue js库并尝试在库中发送该pdf内容

试试这个 Get help from here

答案 2 :(得分:0)

对我有用。

从laravel后端:

$pdf = PDF::loadView('your_view_name', ['data' => $data]);
return $pdf->output();

来自vuejs前端:

axios({
url: 'http://localhost:8000/api/your-route',
method: 'GET',
responseType: 'blob',
}).then((response) => {
     var fileURL = window.URL.createObjectURL(new Blob([response.data]));
     var fileLink = document.createElement('a');
     fileLink.href = fileURL;
     fileLink.setAttribute('download', 'file.pdf');
     document.body.appendChild(fileLink);
     fileLink.click();

});

答案 3 :(得分:-1)

downloadFile: function () {
            this.$http.post('{{ route('download.download') }}', {
                _token: "{{ csrf_token() }}",
                inputs: this.inputs
            },{responseType: 'arraybuffer'}).then(response => {
                var filename = response.headers.get('content-disposition').split('=')[1].replace(/^\"+|\"+$/g, '')
                var url = window.URL.createObjectURL(new Blob([response.body],{type:response.headers.get('content-type')}))
                var link = document.createElement('a')
                link.href = url
                link.setAttribute('download', filename)
                document.body.appendChild(link)
                link.click()
            });
        },