web-dev-qa-db-ja.com

Vue + Laravel:PDFファイルを適切にダウンロードするには?

状況:

フロントエンド:Vue。バックエンド:Laravel。

Webアプリ内で、ユーザーに特定のpdfファイルをダウンロードさせる必要があります。

  • ファイルを取得してAPI GETリクエストの応答として返すには、Laravelが必要です。
  • 次に、Vue Webアプリ内でファイルを取得してダウンロードする必要があります。

コード:

API:

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

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

Webアプリ:

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

質問:

APIのLaravelおよびWebアプリのVueを使用してPDFファイルを適切にダウンロードするにはどうすればよいですか?

ありがとう!

7
FrancescoMussi

解決策:

適切なクレジットは@Sagarに送られ、正しい方向に導かれます。

上記のコードは正しかった。欠落していたのは、適切なresponseTypearraybufferとして追加することでした。

私はそれらに怖がった????応答内で、それは私を誤解させていました。 pdfはバイナリデータであり、適切な読者が読むことを目的としているため、これらの疑問符は大丈夫でした。

配列バッファ:

また、arraybufferは、バイナリデータを保持するために正確に使用されます。

これは、Mozilla Webサイトの定義です。

ArrayBufferオブジェクトは、一般的な固定長の生のバイナリデータバッファーを表すために使用されます。 ArrayBufferの内容を直接操作することはできません。代わりに、特定の形式でバッファを表す型付き配列オブジェクトまたはDataViewオブジェクトの1つを作成し、それを使用してバッファの内容を読み書きします。

ResponseType文字列は、応答のタイプを示します。配列バッファーを指定することにより、データを適切に処理します。

そして、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)
},
16
FrancescoMussi