无法通过 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 响应数据从对象中获取特定字段

vue js中的axios将请求作为字符串而不是对象发送

使用 Vue.js 和 Axios 向 Mailchimp 提交表单会导致 CORS 错误

vue.js 和 axios 使用但无法在 response.headers 中接收 set-cookie