Laravel 校验FormData提交的JSON字符串数组类全量数据失效问题
核心问题根因
你现在的校验完全失效,本质是字段类型和校验规则不匹配:
- 前端构建FormData时,除了photo、cv两个文件,所有字段都统一执行
JSON.stringify后追加到请求里 - 以
multipart/form-data格式传输的请求,服务端默认不会自动对JSON字符串做解码——也就是说后端拿到的languages、educations本质是字符串,不是PHP可识别的数组结构,哪怕你写了required|array规则,也会直接判定类型不匹配,校验不通过。 - 顺带提醒:哪怕是name、email这类普通标量字段,你现在的逻辑也会把它们转成带双引号的JSON字符串,只是因为没触发类型校验规则暂时没暴露异常。
注意:不要尝试在校验规则里链式写required|json|array来解决问题——json规则只会校验字符串格式是否合法,不会自动把字符串解码成数组供后续规则使用,完全不生效。
可落地的修正方案
方案1:优先修正前端FormData构建逻辑
不要对所有非文件字段统一做JSON序列化,区分字段类型处理:
let fd = new FormData(); // 仅对真正的嵌套结构字段做序列化 const needSerializeKeys = ['educations', 'languages', 'trainings']; Object.keys(this.application).forEach((key) => { const fieldValue = this.application[key]; // 单独处理文件类型字段 if (key === 'photo' || key === 'cv') { fd.append(key, fieldValue); return; } // 数组/对象类型字段序列化后追加 if (needSerializeKeys.includes(key)) { fd.append(key, JSON.stringify(fieldValue)); return; } // 普通字符串/数字字段直接传原始值 fd.append(key, fieldValue); });
方案2:如果无法改动前端逻辑,服务端做前置解码适配
在执行校验前,先把前端传来的JSON字符串格式字段手动解码成PHP数组,再传给校验器:
// 取全量请求数据 $validatedDataPayload = $request->all(); // 需要解码的JSON格式字段 $jsonDecodeFields = ['educations', 'languages', 'trainings']; foreach ($jsonDecodeFields as $field) { if (isset($validatedDataPayload[$field]) && is_string($validatedDataPayload[$field])) { $decodedValue = json_decode($validatedDataPayload[$field], true); // 解码成功则替换为实际数组值 if (json_last_error() === JSON_ERROR_NONE) { $validatedDataPayload[$field] = $decodedValue; } } } // 传入解码后的数据执行校验 $validator = \Validator::make($validatedDataPayload, [ "name" => "required|max:255", "email" => "required|max:255", "district_id" => "required|max:11", "division_id" => "required|max:11", "upazila_id" => "required|max:11", "address_details" => "required|max:255", "training" => "required", "languages" => "required|array", "educations" => "required|array", "educations.*.exam_name" => "required|max:255", "educations.*.university_name" => "required|max:255", "educations.*.board_name" => "required|max:255", "educations.*.result" => "required", "photo" => "required|image|mimes:jpeg,png,jpg,gif,svg|max:2048", "cv" => "required|file|mimes:doc,pdf,docx|max:2048", "trainings.*.name" => 'required_if:training,Yes', "trainings.*.description" => 'required_if:training,Yes' ]);
现有代码的额外注意事项
- 校验规则里
training字段重复定义了两次,PHP数组会自动以后一次覆盖前一次,虽然后果不严重,但建议删掉重复配置 - 校验规则里的嵌套字段路径(比如
educations.*.exam_name),必须和解码后的数组结构完全对应,否则也会触发校验不匹配 - 若前端传的JSON字符串格式非法,建议补充格式合法性校验,直接返回“字段格式错误”的提示,避免校验逻辑误判
内容的提问来源于stack exchange,提问作者proghasan
相关产品推荐
相关产品推荐

