Laravel FormRequest验证GET请求JSON查询参数失效排查
问题分析与解决方案
核心问题在于你用json_decode()解码JSON字符串时返回的是PHP stdClass对象,而Laravel的嵌套数组验证规则(如*.name)仅对关联数组生效。当验证器遇到对象时,无法解析嵌套属性的验证规则,只会执行顶层的required和array检查,嵌套规则直接跳过,同时会将无法验证的对象属性置空,但不会触发422验证失败响应。
修复步骤
1. 将JSON解码为关联数组
修改prepareForValidation()中的json_decode调用,添加第二个参数true,强制返回关联数组:
protected function prepareForValidation(): void { try { $sorters = null; if ($this->query->has('sorters')) { // 解码为关联数组 $sorters = json_decode($this->query->get('sorters'), true); $this->merge([ 'sorters_decoded' => $sorters, ]); } $filters = null; if ($this->query->has('filters')) { // 解码为关联数组 $filters = json_decode($this->query->get('filters'), true); $this->merge([ 'filters_decoded' => $filters, ]); } $this->merge([ 'language' => $this->headers->get('language'), ]); } catch(\Throwable $e) { // 可在此处记录日志,无需静默忽略 // Log::error('JSON解码失败: ' . $e->getMessage()); } }
2. 调整可选参数的验证规则(可选)
如果sorters和filters是可选查询参数,需要将对应的_decoded字段规则从required改为nullable,同时给嵌套规则添加required_with约束,避免用户未传参数时触发不必要的验证失败:
public function rules(): array { return [ 'sorters' => ['nullable', 'json'], 'sorters_decoded' => ['nullable', 'array'], 'sorters_decoded.*.name' => ['required_with:sorters_decoded', 'string', Rule::in(['likes', 'ratings', 'calories', 'carbs', 'protein', 'fat', 'created'])], 'sorters_decoded.*.direction' => ['required_with:sorters_decoded', 'string', Rule::in(['asc', 'desc'])], 'sorters_decoded.*.order' => ['required_with:sorters_decoded', 'integer'], 'filters' => ['nullable', 'json'], 'filters_decoded' => ['nullable', 'array'], 'filters_decoded.duration_high' => ['required_with:filters_decoded', 'integer', 'min:0'], 'filters_decoded.duration_low' => ['required_with:filters_decoded', 'integer', 'min:0'], 'filters_decoded.title' => ['required_with:filters_decoded', 'string'], 'filters_decoded.difficulty' => ['required_with:filters_decoded', 'array'], 'filters_decoded.difficulty.*' => ['string', 'exists:difficulties,id'], 'filters_decoded.ingredients' => ['required_with:filters_decoded', 'array'], 'filters_decoded.ingredients.*.id' => ['string', 'exists:ingredients,id'], 'filters_decoded.ingredients.*.relation' => ['string', Rule::in(['include', 'exclude'])], 'filters_decoded.liked_by_me' => ['required_with:filters_decoded', 'boolean'], 'filters_decoded.cookbooks' => ['required_with:filters_decoded', 'array'], 'filters_decoded.cookbooks.*' => ['string', 'exists:cookbooks,id'], 'filters_decoded.nutritions' => ['required_with:filters_decoded', 'array'], 'filters_decoded.nutritions.*.category_id' => ['string', 'exists:nutrition_categories,id'], 'filters_decoded.nutritions.*.nutrition_high' => ['numeric', 'min:0'], 'filters_decoded.nutritions.*.nutrition_low' => ['numeric', 'min:0'], 'language' => ['string', 'size:2', 'exists:i18n_languages,short'], 'page' => ['integer', 'min:1'], 'per_page' => ['integer', 'min:1'], ]; }
3. 强化JSON解码失败处理(可选)
虽然sorters和filters已添加json规则,Laravel会自动验证格式,但如果需要更明确的错误提示,可以在解码后主动检查结果:
if ($this->query->has('sorters')) { $sorters = json_decode($this->query->get('sorters'), true); if (json_last_error() !== JSON_ERROR_NONE) { // 手动触发JSON格式验证失败 $this->merge(['sorters' => 'invalid_json']); } $this->merge(['sorters_decoded' => $sorters]); }
验证逻辑说明
当JSON被解码为关联数组后,Laravel的验证器可以正确识别嵌套结构,执行元素级规则校验。一旦数据不符合规则,会立即返回422响应并携带具体错误信息,而非仅置空非法数据。
内容的提问来源于stack exchange,提问作者MikkeyDevelop
相关产品推荐
相关产品推荐

