Vue + Laravel:如何正确下载PDF文件?
情况:
前端:Vue.后端:Laravel.
Frontend: Vue. Backend: Laravel.
在网络应用程序中,我需要让用户下载某些pdf文件:
Inside the web app I need to let the user download certain pdf files:
- 我需要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是空白的.
Using this code I do manage to download a pdf file. The problem is that the pdf is blank.
以某种方式破坏数据(不是这个特定pdf文件的问题,我尝试了多个pdf文件-结果相同)
Somehow the data got corrupted (not a problem of this particular pdf file, I have tried with several pdf files - same outcome)
来自服务器的响应:
来自服务器的响应本身很好:
The response itself from the server is fine:
PDF:
问题可能出在pdf文件上.它肯定看起来已损坏的数据.这是response.data
的摘要:
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
:
问题:
如何使用Laravel的API和Vue的Web应用程序正确下载pdf文件?
How can I properly download a pdf file using Laravel for the API and Vue for the web app?
谢谢!
解决方案:
应归功于@Sagar,以向我指出正确的方向.
Due credits goes to @Sagar to point me in the right direction.
上面的代码是正确的.缺少的是将适当的responseType
添加为arraybuffer
.
The code above was correct. What was missing was adding the proper responseType
as arraybuffer
.
我对回答中的????
感到害怕,这误导了我.
这些问号没问题,因为pdf是二进制数据,并且应由适当的读者阅读.
I got scared by those ????
inside the response, and that was misleading me.
Those question marks were just okay since pdf is a binary data and is meant to be read by a proper reader.
ARRAYBUFFER:
而arraybuffer恰好用于保留二进制数据.
And arraybuffer is precisely used to keep binary data.
这是来自mozilla网站的定义:
This is the definition from the mozilla website:
ArrayBuffer对象用于表示通用的固定长度 原始二进制数据缓冲区.您不能直接操纵 ArrayBuffer;而是创建一个类型化数组对象之一,或者 一个DataView对象,它以特定格式表示缓冲区, 并使用它来读取和写入缓冲区的内容.
The ArrayBuffer object is used to represent a generic, fixed-length raw binary data buffer. You cannot directly manipulate the contents of an ArrayBuffer; instead, you create one of the typed array objects or a DataView object which represents the buffer in a specific format, and use that to read and write the contents of the buffer.
ResponseType
字符串表示响应的类型.通过告诉它一个arraybuffer,然后它会相应地处理数据.
And the ResponseType
string indicates the type of the response. By telling its an arraybuffer, it then treats the data accordingly.
通过添加responseType,我设法正确下载了pdf文件.
And just by adding the responseType I managed to properly download the pdf file.
代码:
这是经过更正的Vue代码(与以前完全一样,但是添加了responseType):
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()
})
}
这是一个更完整的解决方案,其中考虑了其他浏览器的行为:
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)
},