THE SITUATION:

前端:VUE.后端:Laravel.

Inside the web app I need to let the user download certain pdf files:

  • I need Laravel to take the file and return it as a response of an API GET request.
  • Then inside my Vue web app I need to get the file and download it.

THE CODE:

API:

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

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

Web app:

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()
    })
}

OUTCOME:

使用这段代码,我确实下载了一个pdf文件.问题是pdf是空白的.

不知怎的,数据被 destruct 了(这不是这个特定pdf文件的问题,我try 了几个pdf文件——结果相同)

RESPONSE FROM SERVER:

服务器本身的响应正常:

enter image description here

PDF:

The problem may be with the pdf file. It definitely looks corrupted data. This is an excerpt of how it looks like the response.data:

enter image description here

THE QUESTION:

How can I properly download a pdf file using Laravel for the API and Vue for the web app?

谢谢!

推荐答案

SOLUTION:

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

我被回复中的????条吓到了,这误导了我.

THE ARRAYBUFFER:

And arraybuffer is precisely used to keep binary data.

这是mozilla网站上的定义:

ArrayBuffer对象用于表示通用的固定长度

And the ResponseType string indicates the type of the response. By telling its an arraybuffer, it then treats the data accordingly.

通过添加responseType,我成功地下载了pdf文件.

THE CODE:

This is corrected Vue code (exactly as before, but with the addition of the 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()
    })
}

EDIT:

This is a more complete solution that take into account other browsers behavior:

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)
},

Laravel相关问答推荐

为什么Laravel在API请求时返回BadMethodCallException?

Laravel中如何动态更改路由链接?

为什么删除查询执行 Laravel

在 Laravel 中设置多个 Vue 组件的问题

将数据从控制器传递到 Laravel 中的视图

处理程序类中的错误 - Laravel

如何防止 Laravel 路由被直接访问(即非 ajax 请求)

具有实时和 WebSockets 的 Angular2 + Laravel

Laravel 路由将变量传递给控制器

致命错误:找不到类App\Http\Controllers\Redirect

Laravel 5 文件下载:stream() 或 download()

Laravel 5 - 多对多 - Attach versus Save

如何在 Laravel 中创建类别的嵌套列表?

WhereNotExists Laravel Eloquent

Auth 在 Laravel Tinker 中不起作用

如何使用命令行手动运行 laravel/lumen 作业(job)

在 laravel 的测试套件中只运行一个单元测试

如何在 Laravel 5.3 中获取当前的语言环境

为什么`catch (Exception $e)` 不处理这个`ErrorException`?

如何从 laravel 5.1 中数据库表的 created_at 属性中 Select 年份和月份?