Laravel使用Maatweb/AJAX实现Excel导入表单验证422报错排查
Laravel 结合Maatwebsite Excel实现导入功能422错误无法前端提示修复
核心问题原因
现有代码存在4个问题导致错误无法正常展示:
- jQuery AJAX默认仅将2xx状态码的响应归入
success回调逻辑,后端返回422状态码时会直接进入错误分支,现有代码未配置error回调,无法捕获响应内容,仅能在控制台看到422状态报错 - 后端异常捕获块中遍历错误集合时,首次循环就直接return响应,仅会返回第一条验证错误,丢失其余错误、错误对应Excel行号等关键信息
- 前端注释代码中状态码书写错误,误将422写为442,即使进入成功分支也无法匹配判断
- 上传的Excel文件移动到public目录后未做清理,长期运行会产生大量垃圾临时文件
修改后代码
1. 控制器方法 EmployeeController@import_excel
public function import_excel(Request $request) { if($request->ajax()){ $file = $request->file('file'); $nama_file = rand().$file->getClientOriginalName(); $file->move('file_employee', $nama_file); $filePath = public_path('/file_employee/'.$nama_file); try { Excel::import(new EmployeeImport, $filePath); // 导入完成删除临时文件 unlink($filePath); return response()->json([ 'status' => 200, 'message' => '导入成功' ]); } catch (\Maatwebsite\Excel\Validators\ValidationException $e) { // 导入失败也要删除临时文件 unlink($filePath); $failures = $e->failures(); $errorList = []; foreach($failures as $failure) { // 收集所有错误,附带对应Excel行号 $errorList[] = [ 'row' => $failure->row(), // 错误所在Excel行号 'attribute' => $failure->attribute(), // 错误字段 'errors' => $failure->errors(), // 具体错误信息 ]; } return response()->json([ 'status' => 422, 'message' => '导入数据验证失败', 'errors' => $errorList, ], 422); // 明确设置响应状态码为422 } } }
2. 前端AJAX逻辑 v_employee.blade
$("#importpost").on("submit", function(e) { e.preventDefault(); var extension = $('#file_upload').val().split('.').pop().toLowerCase(); if ($.inArray(extension, ['csv', 'xls', 'xlsx']) == -1) { alert('请选择 csv/xls/xlsx 格式的文件!'); return false; } var file_data = $('#file_upload').prop('files')[0]; var form_data = new FormData(); form_data.append('file', file_data); $.ajaxSetup({ headers: { 'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content') } }); // 发起请求前先清空之前的错误提示 $('#importform_errList').hide().html('').removeClass('alert alert-danger'); $.ajax({ url: "{{route('employee.import')}}", data: form_data, type: 'POST', contentType: false, cache: false, processData: false, success: function(response) { if(response.status == 200){ alert(response.message); $('#importExcel').modal('hide'); tampil_table(); // 重置文件选择框 $('#file_upload').val(''); } }, // 新增error回调处理非2xx状态响应 error: function(xhr){ if(xhr.status == 422){ let res = xhr.responseJSON; $('#importform_errList').show().addClass('alert alert-danger'); $('#importform_errList').append('<p>'+ res.message +'</p>'); $('#importform_errList').append('<ul>'); // 遍历所有错误信息展示 res.errors.forEach(function(err){ err.errors.forEach(function(msg){ $('#importform_errList ul').append('<li>第'+ err.row +'行:'+ msg +'</li>'); }) }) $('#importform_errList').append('</ul>'); }else{ alert('请求失败,请稍后重试'); } } }); });
(可选优化)导入类 EmployeeImport
可以直接使用Maatwebsite提供的WithValidation接口替代手动写Validator,框架会自动处理验证抛出异常,代码更简洁:
<?php namespace App\Imports; use App\Models\Employee; use Maatwebsite\Excel\Concerns\ToCollection; use Maatwebsite\Excel\Concerns\WithValidation; use Illuminate\Support\Collection; class EmployeeImport implements ToCollection, WithValidation { public function collection(Collection $rows) { foreach ($rows as $row) { Employee::create([ 'nik' => $row['nik'], 'name' => $row['name'], 'id_department' => $row['id_department'], 'id_position' => $row['id_position'], 'id_group' => $row['id_group'], 'id_meet_point' => $row['id_meet_point'], ]); } } // 定义验证规则,框架自动验证 public function rules(): array { return [ '*.nik' => 'required', '*.name' => 'required', '*.id_department' => 'required', '*.id_position' => 'required', '*.id_group' => 'required', '*.id_meet_point' => 'required', ]; } }
页面中需要提前存在错误展示容器:
<div id="importform_errList"></div>,放在表单合适位置即可。
内容的提问来源于stack exchange,提问作者Eka
相关产品推荐
相关产品推荐

