Laravel+InertiaJS导出Excel返回302无响应问题求助
Laravel 10 + InertiaJS + Laravel Excel导出返回302问题解决
问题描述
在Laravel 10项目中结合InertiaJS使用laravel-excel包实现Excel导出时,exportMPR接口始终返回302状态码且无文件下载响应。尝试过存储文件后获取、输出原始数据等方法,均未解决,期望实现直接文件下载或返回Blob数据。
核心原因
- InertiaJS请求的局限性:Inertia的表单请求(如
post方法)是为JSON交互设计的,无法识别后端返回的文件下载响应(带Content-Disposition头),会将非JSON响应视为异常,触发框架内部逻辑导致302重定向。 - 认证中间件的判断逻辑:虽然认证中间件中写了
$request->expectsJson() ? null : route('login'),但Inertia请求的Accept头并非application/json,导致expectsJson()返回false,一旦请求处理不符合预期,就会被重定向到登录页,出现302状态码。
解决方案
方式一:直接触发浏览器下载(推荐)
后端路由调整
将POST路由改为GET(下载场景用GET更符合REST规范):
// web.php Route::middleware('auth')->group(function () { Route::controller(MPRController::class)->name('mpr.')->prefix('mpr')->group(function (): void { Route::get('export-mpr', 'exportMPR')->name('exportMPR'); }); });
前端逻辑调整
替换原Inertia表单提交,用原生方式触发下载:
<script setup> const downloadMPR = () => { const { year, monthIndex } = downloadMPRForm.yearMonth; // 拼接参数并打开新窗口下载 window.open(`/mpr/export-mpr?year=${year}&month=${monthIndex}`, '_blank'); } </script> <template> <!-- 替换原表单按钮 --> <button type="button" class="text-white bg-blue-700 focus:outline-none font-medium rounded-lg text-sm px-5 py-2.5" :disabled="downloadMPRForm.processing" :class="{ 'opacity-25': downloadMPRForm.processing }" @click="downloadMPR"> Submit </button> </template>
方式二:返回Blob并手动触发下载(适用于必须用POST的场景)
后端控制器调整
生成Excel二进制数据并返回,设置正确响应头:
// MPRController.php use Illuminate\Support\Facades\Response; use Maatwebsite\Excel\Facades\Excel; public function exportMPR() { try { // 生成Excel原始内容 $excelContent = Excel::raw(new MPRExport(request('month'), request('year')), \Maatwebsite\Excel\Excel::XLSX); // 返回二进制数据及下载头 return Response::make($excelContent, 200, [ 'Content-Type' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'Content-Disposition' => 'attachment; filename="mpr.xlsx"', ]); } catch (Exception $e) { return response()->json(['error' => $e->getMessage()], 500); } }
前端逻辑调整
用原生fetch处理Blob响应,手动触发下载:
<script setup> const downloadMPR = async () => { const { year, monthIndex } = downloadMPRForm.yearMonth; downloadMPRForm.processing = true; try { const response = await fetch('/mpr/export-mpr', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').content, 'X-Requested-With': 'XMLHttpRequest' // 让认证中间件识别为AJAX请求 }, body: JSON.stringify({ year, month: monthIndex }), }); if (!response.ok) throw new Error('下载失败'); const blob = await response.blob(); const url = window.URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = 'mpr.xlsx'; document.body.appendChild(a); a.click(); window.URL.revokeObjectURL(url); document.body.removeChild(a); } catch (err) { console.error(err); // 可添加前端错误提示 } finally { downloadMPRForm.processing = false; } } </script>
关键注意事项
- 避免用Inertia的
post/get方法处理文件下载:Inertia核心是SPA页面交互,不支持直接解析文件下载响应。 - 认证中间件适配:POST请求需添加
X-Requested-With: XMLHttpRequest头,确保$request->expectsJson()返回true,防止被重定向到登录页。
内容的提问来源于stack exchange,提问作者HV Sharma
相关产品推荐
相关产品推荐

