Laravel提交表单时未传nullable文件触发异常问题求助
问题分析与解决方案
问题根源
- 你的
UploadImageAction::handle方法中,无论字段是否为必填,只要$storedImage为NULL(包括可选字段未上传的情况),就会抛出ImageUploadException。而handoverStatement是可选字段,未上传时$storedImage为NULL,直接触发异常,导致后续流程中断,同时已经上传的LFImage无法回滚。 - 控制器中未区分必填/可选字段,直接调用
handle处理handoverStatement,即使没有上传文件也会执行上传逻辑,触发异常。
修复方案
方案1:修改UploadImageAction,支持可选字段处理
给handle方法增加一个$required参数,默认true,用于区分字段是否必填。仅当必填字段未上传/上传失败时抛出异常,可选字段未上传则返回NULL:
class UploadImageAction implements UploadImageContract { public function handle(Request $request, $image, $imageLocation, bool $required = true) { if (!$request->hasFile($image)) { if ($required) { throw new ImageUploadException("The {$image} field is required."); } return null; } $storedImage = $request->file($image)->store($imageLocation); if (!$storedImage) { throw new ImageUploadException("Failed to upload {$image}."); } return $storedImage; } }
然后在控制器中调用时,给handoverStatement传入$required = false:
// Add new Record. public function store(LostFoundRequest $request, LostFoundService $lostFoundService, UploadImageContract $uploadImageAction) { try { $LFImage = $uploadImageAction->handle($request, 'LFImage', 'lostFound/lostItems'); // 必填字段,默认true $handoverStatement = $uploadImageAction->handle($request, 'handoverStatement', 'lostFound/handoverStatements', false); // 可选字段,传入false $lostFoundService->storeLostFound($request, $LFImage, $handoverStatement); return redirect('data-entry/lost-and-found')->with('success', 'Item Added Successfully'); } catch (ImageUploadException $exception) { // 清理已上传的LFImage,避免产生垃圾文件 if (isset($LFImage)) { \Illuminate\Support\Facades\Storage::delete($LFImage); } return back()->withErrors($exception->getMessage()); } catch (LostFoundException $exception) { // 清理已上传的所有图片 if (isset($LFImage)) { \Illuminate\Support\Facades\Storage::delete($LFImage); } if (isset($handoverStatement)) { \Illuminate\Support\Facades\Storage::delete($handoverStatement); } return back()->withErrors('lostFound', $exception->getMessage()); } catch (\Throwable $exception) { // 异常时清理已上传文件 if (isset($LFImage)) { \Illuminate\Support\Facades\Storage::delete($LFImage); } if (isset($handoverStatement)) { \Illuminate\Support\Facades\Storage::delete($handoverStatement); } throw $exception; } }
方案2:控制器中先判断是否有文件,再调用上传方法
如果不想修改UploadImageAction,可以在控制器中先检查handoverStatement是否存在文件,再决定是否调用上传逻辑:
// Add new Record. public function store(LostFoundRequest $request, LostFoundService $lostFoundService, UploadImageContract $uploadImageAction) { try { $LFImage = $uploadImageAction->handle($request, 'LFImage', 'lostFound/lostItems'); $handoverStatement = null; if ($request->hasFile('handoverStatement')) { $handoverStatement = $uploadImageAction->handle($request, 'handoverStatement', 'lostFound/handoverStatements'); } $lostFoundService->storeLostFound($request, $LFImage, $handoverStatement); return redirect('data-entry/lost-and-found')->with('success', 'Item Added Successfully'); } catch (ImageUploadException $exception) { // 清理已上传的LFImage if (isset($LFImage)) { \Illuminate\Support\Facades\Storage::delete($LFImage); } return back()->withErrors($exception->getMessage()); } catch (LostFoundException $exception) { // 清理已上传的所有图片 if (isset($LFImage)) { \Illuminate\Support\Facades\Storage::delete($LFImage); } if (isset($handoverStatement)) { \Illuminate\Support\Facades\Storage::delete($handoverStatement); } return back()->withErrors('lostFound', $exception->getMessage()); } catch (\Throwable $exception) { // 异常时清理已上传文件 if (isset($LFImage)) { \Illuminate\Support\Facades\Storage::delete($LFImage); } if (isset($handoverStatement)) { \Illuminate\Support\Facades\Storage::delete($handoverStatement); } throw $exception; } }
关键补充:异常时清理已上传文件
无论采用哪种方案,都需要在捕获异常时删除已经成功上传的图片,避免服务器产生垃圾文件。上述代码中已加入该逻辑,确保Storage facade已正确引入(可在控制器顶部添加use Illuminate\Support\Facades\Storage;简化代码)。
内容的提问来源于stack exchange,提问作者Abdulrahman Mushref
相关产品推荐
相关产品推荐

