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

Laravel如何向React前端返回多个docx文件?

Laravel后端向React前端返回多文件问题

使用技术栈:PHP(Laravel框架)、JavaScript(React框架)

我需要从Laravel后端向React前端返回多个docx文件,目前单文件返回功能正常,但不知道如何实现多文件返回。$generatedFiles是包含所有待返回docx文件路径的数组。


现有代码

后端代码(待修改)

$generatedFiles[] = public_path() . '/' . $fileName . '.docx';  
return response()->file(此处需返回generatedFiles中的所有文件);

单文件返回可行代码

return response()->file(public_path() . '/' . $fileName . '.docx');

前端接收响应代码(React)

export const postProject = (datas) => async (dispatch) => {
  console.log(datas);
  dispatch(setPostLoading(true));

  await axios({
    method: 'post',
    url: `${process.env.REACT_APP_API}/api/projects`,
    data: datas,
    responseType: 'blob',
    headers: {
      Accept:
        'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
    },
  }).then((res) => {
    if (!res.data) {
      dispatch(setError(true));
    } else {
      var blob = new Blob([res.data], {
        type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
      });
      saveAs(blob, 'test.docx');
    }
  });
  dispatch(setPostLoading(false));
};

已尝试的方案

  1. 打包Zip文件返回,但报错“压缩的Zip文件夹无效”
    相关代码:
foreach ($generatedFiles as $file) {
    $zip->addFile($file, basename($file)); // 将每个生成的docx文件添加到Zip中
}

$zip->close();

// 读取Zip文件内容并作为响应返回
$fileContents = file_get_contents($zipPath);
$response = response()->make($fileContents, 200, [
    'Content-Type' => 'application/zip',
    'Content-Disposition' => 'attachment; filename="generated_files.zip"',
]);

// 清理临时文件
unlink($zipPath);

return $response;
  1. 返回JSON格式的文件路径数组,但前端遍历后不知道如何处理每个元素
    相关代码:
return response()->json($generatedFiles);

解决方案

方案一:修复Zip打包返回(推荐)

之前的Zip方案报错,大概率是文件创建过程存在权限问题、文件不存在或Zip实例初始化错误,按以下步骤调整:

后端代码调整

use ZipArchive;
use Illuminate\Support\Facades\Storage;

// 初始化Zip实例
$zip = new ZipArchive();
$zipName = 'generated_files.zip';
// 用storage目录存储临时Zip,避免权限问题
$zipPath = storage_path('app/temp/' . $zipName);

// 确保临时目录存在
if (!file_exists(storage_path('app/temp'))) {
    mkdir(storage_path('app/temp'), 0755, true);
}

// 打开Zip文件,CREATE模式自动创建/覆盖文件
if ($zip->open($zipPath, ZipArchive::CREATE) === TRUE) {
    foreach ($generatedFiles as $file) {
        // 先验证文件存在,避免无效文件损坏Zip
        if (file_exists($file)) {
            $zip->addFile($file, basename($file));
        }
    }
    $zip->close();

    // 用Laravel自带的file响应返回,自动处理头信息
    $response = response()->file($zipPath, [
        'Content-Disposition' => 'attachment; filename="' . $zipName . '"',
        'Content-Type' => 'application/zip',
    ]);

    // 响应结束后清理临时文件,避免占用空间
    register_shutdown_function(function () use ($zipPath) {
        if (file_exists($zipPath)) {
            unlink($zipPath);
        }
    });

    return $response;
} else {
    return response()->json(['error' => '无法创建压缩文件'], 500);
}

前端代码调整

修改请求头和响应逻辑,适配Zip类型:

export const postProject = (datas) => async (dispatch) => {
  console.log(datas);
  dispatch(setPostLoading(true));

  try {
    const res = await axios({
      method: 'post',
      url: `${process.env.REACT_APP_API}/api/projects`,
      data: datas,
      responseType: 'blob',
      headers: {
        Accept: 'application/zip', // 调整Accept头为Zip类型
      },
    });

    if (!res.data) {
      dispatch(setError(true));
      return;
    }

    const blob = new Blob([res.data], { type: 'application/zip' });
    saveAs(blob, 'generated_files.zip');
  } catch (error) {
    dispatch(setError(true));
  } finally {
    dispatch(setPostLoading(false));
  }
};

方案二:返回文件URL数组,前端逐个下载

如果不想用Zip,可返回文件的可访问URL,前端循环请求下载:

后端代码

// 将本地路径转为前端可访问的URL
$fileUrls = array_map(function ($file) {
    return asset(str_replace(public_path(), '', $file));
}, $generatedFiles);

return response()->json(['files' => $fileUrls]);

前端代码

import axios from 'axios';
import { saveAs } from 'file-saver';

export const postProject = (datas) => async (dispatch) => {
  console.log(datas);
  dispatch(setPostLoading(true));

  try {
    const res = await axios({
      method: 'post',
      url: `${process.env.REACT_APP_API}/api/projects`,
      data: datas,
    });

    if (!res.data?.files) {
      dispatch(setError(true));
      return;
    }

    // 遍历URL逐个下载
    for (const url of res.data.files) {
      const fileRes = await axios({
        url,
        responseType: 'blob',
      });
      const fileName = url.split('/').pop();
      const blob = new Blob([fileRes.data], { 
        type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' 
      });
      saveAs(blob, fileName);
    }
  } catch (error) {
    dispatch(setError(true));
  } finally {
    dispatch(setPostLoading(false));
  }
};

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 16:07:14