You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel Inertia/Vue3提交表单下载文件返回302重定向问题

问题原因

Inertia的useForm.post()本质是发送AJAX请求,但浏览器不会自动触发文件下载动作来处理AJAX响应中的文件流。Laravel的response()->download()在这种场景下,会被Inertia的默认逻辑识别为页面跳转请求,最终导致302重定向并刷新页面,无法触发下载。

解决方案

方案一:后端生成临时签名URL,前端跳转

后端生成动态文件后,创建一个带签名的临时下载链接,通过Inertia的location()方法触发前端跳转,让浏览器处理下载:

  1. 修改控制器代码:
use Illuminate\Http\Request;
use Illuminate\Support\Facades\URL;

public function __invoke(Request $request)
{
    // 保留你的动态生成文件逻辑
    $path = '/some/path/to/report.xls';
    $filename = 'report.xls';

    // 生成有效期5分钟的签名URL,防止非法访问
    $downloadUrl = URL::temporarySignedRoute(
        'temp.download',
        now()->addMinutes(5),
        ['path' => $path, 'filename' => $filename]
    );

    // 通知Inertia跳转至下载链接
    return inertia()->location($downloadUrl);
}
  1. 添加临时下载路由:
Route::get('temp-download/{path}/{filename}', function ($path, $filename) {
    if (!URL::hasValidSignature(request())) {
        abort(403);
    }
    return response()->download($path, $filename);
})->name('temp.download');

方案二:前端处理Blob响应,手动触发下载

直接通过AJAX接收文件Blob,前端创建临时下载链接触发下载:

  1. 后端控制器无需大改,确保返回正确的文件响应:
public function __invoke(Request $request)
{
    $path = '/some/path/to/report.xls';
    return response()->download($path, 'report.xls');
}
  1. 修改前端代码(替换useForm逻辑):
<script setup>
import axios from 'axios';
import { useRoute } from 'vue-router';
import { ref } from 'vue';

const route = useRoute();
const some = ref(null);
const fields = ref(null);

const handleSubmit = async () => {
    try {
        const res = await axios.post(route('report'), {
            some: some.value,
            fields: fields.value,
        }, {
            responseType: 'blob' // 必须指定响应类型为Blob
        });

        // 创建临时下载链接并触发下载
        const url = window.URL.createObjectURL(new Blob([res.data]));
        const a = document.createElement('a');
        a.href = url;
        a.download = 'report.xls';
        document.body.appendChild(a);
        a.click();

        // 清理资源
        a.remove();
        window.URL.revokeObjectURL(url);
    } catch (err) {
        console.error('下载失败:', err);
    }
};
</script>

<form @submit.prevent="handleSubmit">
    <input v-model="some" />
    <input v-model="fields" />
    <button type="submit">download</button>
</form>

方案三:使用原生HTML表单提交(最简单)

直接复用Blade中的表单逻辑,绕过Inertia的AJAX处理:

<script setup>
import { page } from '@inertiajs/vue3';
import { ref } from 'vue';

const some = ref(null);
const fields = ref(null);
</script>

<form method="POST" :action="route('report')">
    <!-- 自动带入Inertia提供的CSRF令牌 -->
    <input type="hidden" name="_token" :value="page.props.csrf_token" />
    <input name="some" v-model="some" />
    <input name="fields" v-model="fields" />
    <button type="submit">download</button>
</form>

内容的提问来源于stack exchange,提问作者StR

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 04:42:21