laravel get数组参数验证需显式声明通配符规则,如'foo.*' => ['required', 'integer'],且前端必须传标准格式(?foo[]=1&foo[]=2),否则解析失败;空值、长度限制、动态字段等需针对性处理。

GET 请求中数组参数必须显式声明通配符规则
Laravel 默认把 query string 中的 foo[]=1&foo[]=2 解析为数组,但验证器不会自动展开嵌套结构——如果你写 'foo' => 'required|array',它只校验 foo 是否存在且是数组;若想校验每个元素(比如 foo.* 必须是整数),必须显式写出通配符键名。
- 错误写法:
'foo' => ['required', 'array', 'each:integer']——each规则已废弃,Laravel 10+ 不识别 - 正确写法:
'foo.*' => ['required', 'integer', 'min:1'] - 前端传参格式必须是标准数组形式,如
?foo[]=1&foo[]=5&foo[]=99;?foo=1,5,99或?foo=1&foo=5(无[])会被当字符串处理 - 若 GET 参数含空值(如
?foo[]=1&foo[]=&foo[]=3),required会失败,需改用filled或前置过滤
批量校验多个 GET 数组字段时避免规则重复
当 URL 同时带多个数组参数(如 ?category_ids[]=1&category_ids[]=2&tag_ids[]=a&tag_ids[]=b),逐个写 category_ids.* 和 tag_ids.* 没问题,但若字段名动态生成(如 filter_by[status][]、filter_by[region][]),就不能硬编码键名。
- 推荐在 FormRequest 的
rules()中用request()->query()动态提取所有以filter_by[开头的参数,再循环生成规则 - 注意:不能直接对
filter_by整体做array校验,因为它的值是关联数组(['status' => [...], 'region' => [...]]),需分别处理子键 - 示例片段:
$rules = []; foreach (request()->query('filter_by', []) as $key => $values) { if (is_array($values)) { $rules["filter_by.{$key}.*"] = ['required', 'string']; } } return $rules;
GET 数组参数长度限制与性能边界
URL 长度受浏览器和服务器限制(通常 ≤ 2048 字符),所以 foo[]=1&foo[]=2&... 过长会导致截断或 414 错误。验证层无法阻止该问题,但可设兜底规则防止后端异常。
- 用
size或max控制数组元素数量:'foo.*' => ['max:50'](注意这是对每个元素校验,不是总数) - 要限制总数,规则应写在父级:
'foo' => ['array', 'max:50'],再配合'foo.*' => ['required'] - PHP 默认
max_input_vars为 1000,若数组元素超限,多余参数会被静默丢弃——这个限制比验证规则更早生效,需在 php.ini 中调高 - 不要在验证规则里做数据库查询(如
Rule::exists('tags', 'id')批量查上百个 ID),容易触发 N+1 或超时;应先用array_unique去重,再用一次whereIn查
空数组、缺失数组与 null 值的语义差异
GET 请求中,?foo、?foo[]=、?foo[]=1、?foo 缺失,这四种情况在 Laravel 中解析结果完全不同,验证行为也不同。
-
?foo→request('foo') === '',不是数组,foo.*规则不触发(因键不存在) -
?foo[]=→request('foo') === [''],数组含空字符串,required失败,filled也失败 -
?foo[]=1&foo[]=→['1', ''],部分元素为空,需用filter_var($value, FILTER_SANITIZE_NUMBER_INT)预处理或自定义规则过滤 - 最稳妥做法:在 FormRequest 的
prepareForValidation()中统一处理,例如将空字符串元素剔除:protected function prepareForValidation() { $foo = request('foo', []); $foo = array_values(array_filter($foo, fn($v) => $v !== '')); $this->replace(['foo' => $foo]); }
[]。先确认 request()->all() 输出是否符合预期,再谈规则。











