无法通过 Vue.js(Axios 帖子)从 Laravel 后端下载文件(pdf)
Posted
技术标签:
【中文标题】无法通过 Vue.js(Axios 帖子)从 Laravel 后端下载文件(pdf)【英文标题】:Unable to download a file (pdf) from Laravel backend via Vue.js (Axios post) 【发布时间】:2019-03-04 16:28:50 【问题描述】:我在 Vue 中有一个多步骤表单,一旦我收集了所有信息,我就会将结果发布到 Laravel 控制器。这是该站点的经过身份验证的区域。我正在使用护照。所以基本上我有一个 Vue SPA,它是在 Laravel 5.7 框架内构建的网站的管理区域。
Vue file:
axios.post('/api/quotes/finalize', this.wizardModel)
.then(response =>
if (response.data.success)
//
)
.catch(err =>
if (err.response.status == 401)
window.location.href = '/login';
swal.showValidationError(
`Request failed: $error`
)
)
控制器获取数据并制作 pdf。所有这些都在起作用。然后,它需要查看三个操作 - 通过电子邮件发送 PDF、通过 CC 发送 PDF 以及下载 PDF。
public function finalizeQuote(Request $request)
$data = $request->all();
$data['phone'] = $this->formatTelephone($data['phone']);
$dateStamp = date('Ymdhis', strtotime('now'));
$fileName = 'quote-' . $dateStamp . '.pdf';
$html = View::make('quotes.quote', compact('data'))->render();
$conv = new Converter();
$conv->addPage($html)
->save('storage/' . $fileName);
if ($data['actions']['emailPDF'])
$message = (new Proposal('storage/' . $fileName))
->onConnection('redis')
->onQueue('emails');
if ($data['actions']['carbonCopy'])
Mail::to($data['emailAddress'])
->cc(Auth::user()->email)
->queue($message);
else
Mail::to($data['emailAddress'])->queue($message);
if ($data['actions']['downloadPDF'])
return response()->download(public_path('storage/' . $fileName));
所以在开发工具中,我在响应中看到了 pdf 文件。浏览器中不会发生下载。我确信我只是在这里遗漏了一些基本的东西。
【问题讨论】:
下载请求的响应头中的内容类型是什么? application/pdf 是 Chrome 开发工具中“响应标头”部分下的内容类型。在“请求标头”下是 application/json;charset-UTF-8. 好的,响应标头中是否存在Content-Disposition
标头?如果没有,请将Content-Disposition: attachment; filename="filename.pdf"
添加到响应标头。如果 Content-Disposition 标头存在,请告诉我它的值是什么。
内容配置:附件; filename=quote-20180928035845.pdf 是已经存在的;这是正确的文件名
有趣...您确定要返回的路径中有一个文件吗?还有 $data['actions'] 的价值是什么?
【参考方案1】:
单独的 Ajax 请求不能调用下载。您可以有一个隐藏表单,将您的数据发布到您的 api 端点,这可能是最快的解决方案。
Axios 有一个内置的方法可以轻松做到这一点
axios(
method: 'post',
url: '/api/quotes/finalize',
data: wizardModelFormData,
config: headers: 'Content-Type': 'multipart/form-data'
)
您必须发送表单数据,而不是在请求中发送 json。 设置表单数据对象非常容易,在 FormData 上快速 google 就足够了。
另一种方法是做这样的事情。让端点为您的文件返回一个下载 url,
if ($data['actions']['downloadPDF'])
return response()->json(["download_url" => "/api/download/" . $fileName]);
在客户端,使用window.location
将浏览器位置设置为仅返回文件的api 端点(在本例中为/api/download/fileName)。然后,浏览器将下载从您设置的该位置返回的任何文件(如果您正确设置了标头)。
这意味着您必须实现 /api/download/fileName 路由,但您可以在其中放置类似的内容。
return response()->download(public_path('storage/' . $fileName));
显然,这只是一个简单的解释,不需要完全以相同的方式实现,但它可以理解这个想法。
现在您需要确保不将任何敏感文件放入 storage/ 并设置一些权限。
【讨论】:
这也是一个非常有用的答案。我希望我能接受两者,我最终使用了两者的原则。非常感谢。 @LarryBall 哈哈不用担心,很高兴它有帮助。你总是可以支持我的回答!【参考方案2】:Axios 用于 XHR 请求。通常,下载文件是通过正常的 GET 请求完成的,但在这里您有一个 XHR 发布请求来下载文件。
要通过 AJAX 下载文件,有些人使用库,有些人创建 来自响应的 blob 链接,将其附加到 DOM,然后触发 点击链接。
您可以参考this gist和SO post了解更多详情。
就我个人而言,我更喜欢简单的非 XHR 获取文件下载请求。
【讨论】:
我正在发布整个表单的数据。在控制器中,我正在创建一个 pdf,并根据用户的选择,通过电子邮件发送或让他们下载。我不是说你不正确,也许我试图做的事情是不可能的。 我并不是说您不能使用 XHR 发布请求下载文件。如果您参考要点和 SO 帖子,您可以这样做 知道了。非常感谢。以上是关于无法通过 Vue.js(Axios 帖子)从 Laravel 后端下载文件(pdf)的主要内容,如果未能解决你的问题,请参考以下文章
VUE.JS 通过 webpack-simple 中的 axios 从 url 接收一个 json 文件
如何查询我的 WordPress 博客以列出我的 Vue.js 网站上的最新帖子?
Vue.js - 如何通过 axios 响应数据从对象中获取特定字段