使用maatwebsite/excel:^3.1导出Excel时遭遇60秒超时错误的问题求助
我在使用 maatwebsite/excel:^3.1 包导出数据到Excel时,遇到了60秒执行超时的错误。我暂时还没找到问题所在,也没尝试过相关解决办法,以下是我的代码:
Export类代码(App\Exports\ProductDataExport.php)
namespace App\Exports; use App\Models\Produit; use Illuminate\View\View; use Maatwebsite\Excel\Concerns\Exportable; use Maatwebsite\Excel\Concerns\FromView; use Maatwebsite\Excel\Concerns\ShouldAutoSize; class ProductDataExport implements FromView, ShouldAutoSize { use Exportable; private $products; public function __construct() { $this->products = Produit::all(); } public function view() : View { return view('invoices-product',[ 'products_list' => Produit::all() ]); } }
控制器代码(ProduitController.php)
public function exportProduct() { $product_list = Produit::all(); return Excel::download(new ProductDataExport, 'products-data.xlsx'); }
路由代码
Route::post('products/export-excel',[ProduitController::class, 'exportProduct'])->name('products.download-excel');
表单代码
<form action="{{ route('products.download-excel') }}" method="POST"> @csrf <div> <button type="submit" class="btn btn-success"> <div>Export Excel</div> </button> </div> </form>
问题分析与解决方案
兄弟,先给你梳理下大概率的问题所在:你现在的代码里存在重复查询数据的情况,而且如果你的produit表里数据量不小(比如几千上万条),就很容易触发PHP默认的60秒超时限制。
你看,在ProductDataExport的构造函数里查了一次Produit::all(),结果在view()方法里又查了一次,等于把全量数据加载了两次,这平白增加了服务器的内存和执行时间负担,不超时才怪呢!
下面给你几个一步步解决的办法:
1. 先优化重复查询的问题
先把Export类改一下,只查一次数据,避免做无用功:
namespace App\Exports; use App\Models\Produit; use Illuminate\View\View; use Maatwebsite\Excel\Concerns\Exportable; use Maatwebsite\Excel\Concerns\FromView; use Maatwebsite\Excel\Concerns\ShouldAutoSize; class ProductDataExport implements FromView, ShouldAutoSize { use Exportable; private $products; public function __construct() { // 只查询一次全量数据,存在属性里复用 $this->products = Produit::all(); } public function view() : View { return view('invoices-product',[ 'products_list' => $this->products ]); } }
另外,你控制器里的$product_list = Produit::all();完全是多余的,删掉就行,因为Export类里已经搞定数据查询了:
public function exportProduct() { return Excel::download(new ProductDataExport, 'products-data.xlsx'); }
2. 临时放宽脚本执行时间
要是优化查询后还是超时,说明数据量确实大,可以在导出方法里临时调高PHP的执行时间限制:
public function exportProduct() { // 临时设置成300秒(5分钟),你可以根据实际数据量调整 ini_set('max_execution_time', 300); return Excel::download(new ProductDataExport, 'products-data.xlsx'); }
这种临时设置的方式比直接改php.ini灵活,不会影响其他正常请求的时间限制。
3. 超大量数据就用分批次处理
如果你的数据量达到几万甚至几十万条,那一次性加载全量数据肯定不行,建议改用FromQuery接口,这个接口会自动帮你分批次查询数据,不会把所有数据都塞进内存:
namespace App\Exports; use App\Models\Produit; use Maatwebsite\Excel\Concerns\FromQuery; use Maatwebsite\Excel\Concerns\ShouldAutoSize; class ProductDataExport implements FromQuery, ShouldAutoSize { use Exportable; public function query() { // 直接返回查询构造器就行,包会自动处理分批次 return Produit::query(); } }
不过用这个的话,你可能需要调整导出的视图逻辑,或者直接用表头映射的方式导出(如果不需要自定义视图的话)。
4. 检查导出视图的复杂度
最后再看看你的invoices-product视图,如果里面有很多复杂的循环嵌套、字段计算,也会拖慢渲染速度。尽量把这些计算逻辑提前到Export类或者控制器里处理好,再把处理后的数据传给视图,减少视图的渲染压力。
备注:内容来源于stack exchange,提问作者MOHAMED KESSOUM

