Vue + Laravel:如何正确下载 PDF 文件?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/50736657/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Vue + Laravel: How to properly download a PDF file?
提问by FrancescoMussi
THE SITUATION:
情况:
Frontend: Vue. Backend: Laravel.
前端:vue。后端:Laravel。
Inside the web app I need to let the user download certain pdf files:
在网络应用程序中,我需要让用户下载某些 pdf 文件:
- 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.
- 我需要 Laravel 获取文件并将其作为 API GET 请求的响应返回。
- 然后在我的 Vue Web 应用程序中,我需要获取文件并下载它。
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:
结果:
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)
不知何故,数据被破坏了(不是这个特定 pdf 文件的问题,我已经尝试过几个 pdf 文件 - 结果相同)
RESPONSE FROM SERVER:
服务器的响应:
The response itself from the server is fine:
来自服务器的响应本身很好:
PDF:
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
:
问题可能出在 pdf 文件上。它看起来肯定是损坏的数据。这是它的外观摘录response.data
:
THE QUESTION:
问题:
How can I properly download a pdf file using Laravel for the API and Vue for the web app?
如何使用 Laravel for the API 和 Vue for the web app 正确下载 pdf 文件?
Thanks!
谢谢!
回答by FrancescoMussi
SOLUTION:
解决方案:
Due credits goes to @Sagar to point me in the right direction.
应归功于@Sagar 为我指明了正确的方向。
The code above was correct. What was missing was adding the proper responseType
as arraybuffer
.
上面的代码是正确的。缺少的是添加正确的responseType
as arraybuffer
。
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.
我被????
回复中的那些人吓到了,这误导了我。这些问号没问题,因为 pdf 是二进制数据,应该由适当的读者阅读。
THE ARRAYBUFFER:
数组缓冲区:
And arraybuffer is precisely used to keep binary data.
而arraybuffer正是用来保存二进制数据的。
This is the definition from the mozilla website:
这是来自 mozilla 网站的定义:
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.
ArrayBuffer 对象用于表示通用的、固定长度的原始二进制数据缓冲区。您不能直接操作 ArrayBuffer 的内容;相反,您创建一个类型化数组对象或一个以特定格式表示缓冲区的 DataView 对象,并使用它来读取和写入缓冲区的内容。
And the ResponseType
string indicates the type of the response. By telling its an arraybuffer, it then treats the data accordingly.
并且ResponseType
字符串指示响应的类型。通过告诉它一个数组缓冲区,它然后相应地处理数据。
And just by adding the responseType I managed to properly download the pdf file.
仅通过添加 responseType 我就设法正确下载了 pdf 文件。
THE CODE:
编码:
This is corrected Vue code (exactly as before, but with the addition of the responseType):
这是更正的 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()
})
}
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)
},
回答by Sagar Ahuja
You won't be able to do the download from Laravel
to Vue
since both are running at different ports I assume.
您将无法从Laravel
to进行下载,Vue
因为我假设两者都在不同的端口上运行。
Even if you try something like this.
即使你尝试这样的事情。
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);
}
It won't help as you are sending headers to the Laravel
Port Try using Vue js
libraries and try to send that pdf content on the library
这不会有帮助,因为您将标头发送到Laravel
端口尝试使用Vue js
库并尝试在库上发送该 pdf 内容
Try this Get help from here
试试这个 从这里获取帮助
回答by Edwin Jaimes
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()
});
},