Laravel-excel导出文件无法下载仅存缓存目录问题求助
问题:Laravel Excel导出文件仅保存到缓存目录,不触发浏览器下载
在Laravel项目中使用laravel-excel包导出数据库数据,已能获取正确数据,但文件不会触发浏览器下载,仅保存到storage\framework\cache\laravel-excel目录。
前端Vue代码
<script setup> import { router} from '@inertiajs/vue3'; import { ref } from 'vue' const props = defineProps({transactions:Object}); const status =ref('Status'); const shop =ref('Shop'); const handleExport = ()=>{ const formData = new FormData(); formData.append('status', status.value); formData.append('shop', shop.value); router.post('/export_data', formData,{ preserveState: true, preserveScroll: true, }) } </script> <template> <button @click="handleExport()" type="button"></button> </template>
后端控制器代码
<?php namespace App\Http\Controllers; use App\Exports\TransactionsExport; use App\Models\Transaction; use Illuminate\Http\Request; use Maatwebsite\Excel\Facades\Excel; class TransactionController extends Controller { public function export_data(Request $request) { $status = $request['status']; $shop = $request['shop']; $result = Transaction::where([['status',$status],['shop',$shop]])->get(); return Excel::download(new TransactionsExport($result), 'Transactions.xlsx'); } }
解决方案
原因
Inertia.js的router.post默认处理JSON/HTML类型的响应,无法自动识别并触发Excel这类二进制流的下载操作,导致文件仅被后端缓存而不推送给浏览器。
1. 修改前端代码,用原生Fetch处理下载请求
替换原有的handleExport方法,直接通过Fetch获取二进制响应,手动触发浏览器下载:
<script setup> import { ref } from 'vue' const props = defineProps({transactions:Object}); const status = ref('Status'); const shop = ref('Shop'); const handleExport = async () => { const formData = new FormData(); formData.append('status', status.value); formData.append('shop', shop.value); try { const response = await fetch('/export_data', { method: 'POST', headers: { 'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').content }, body: formData }); if (!response.ok) throw new Error('导出请求失败'); // 处理二进制响应,触发下载 const blob = await response.blob(); const downloadUrl = window.URL.createObjectURL(blob); const link = document.createElement('a'); link.href = downloadUrl; link.download = 'Transactions.xlsx'; document.body.appendChild(link); link.click(); // 清理临时资源 window.URL.revokeObjectURL(downloadUrl); document.body.removeChild(link); } catch (error) { console.error('导出失败:', error); } } </script> <template> <button @click="handleExport()" type="button">导出数据</button> </template>
2. 优化后端控制器(可选)
明确指定响应头,确保Laravel正确输出Excel文件的MIME类型:
<?php namespace App\Http\Controllers; use App\Exports\TransactionsExport; use App\Models\Transaction; use Illuminate\Http\Request; use Maatwebsite\Excel\Facades\Excel; class TransactionController extends Controller { public function export_data(Request $request) { $status = $request->input('status'); $shop = $request->input('shop'); $result = Transaction::where('status', $status) ->where('shop', $shop) ->get(); return Excel::download(new TransactionsExport($result), 'Transactions.xlsx') ->header('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'); } }
关键说明
- Inertia路由仅适用于页面组件交互,不适合处理文件下载这类二进制响应场景。
- 必须携带CSRF令牌,否则Laravel会拦截POST请求。
- 前端通过创建临时链接触发下载是处理二进制文件的标准方式,完成后需清理临时资源避免内存泄漏。
内容的提问来源于stack exchange,提问作者Edson
相关产品推荐
相关产品推荐

