应使用 validate() 返回值或 only() 获取白名单字段,避免直接调用 all();validate() 兼具校验、过滤与类型转换,only() 仅取值无校验;所有入库操作必须基于二者之一,不可信任 all()、except() 或手动过滤。

用 validate 强制只取白名单字段
Laravel 默认不会自动丢弃未定义的请求字段,哪怕你只在 rules 里写了几个字段,其他乱传的参数依然会进 $request->all()。真要“只允许指定字段”,得靠 validate 的隐式行为:它返回的数组就是过滤后的白名单数据,不是原始输入。
常见错误是写完 $request->validate([...]) 还去调 $request->all() —— 这时拿到的仍是全量原始参数,白名单没生效。
- 正确做法:直接用
validate的返回值,比如$data = $request->validate([...]),后续只操作$data - 如果必须复用
$request对象(比如要拿文件),就别用all(),改用$request->only(['name', 'email'])显式取字段 -
validate不仅校验,还自动过滤、类型转换(如'age' => 'integer'会让字符串"18"变成整数18)
别依赖 rules 配置自动过滤
validate 的规则数组(rules)只管校验,不管“删字段”。哪怕你漏写了某个字段的规则,只要没设 required,它照样能进 all() —— 这不是 bug,是设计如此。
典型翻车场景:前端悄悄多传了个 is_admin 字段,后端 rules 没配它,结果 $request->all() 里真出现了这个字段,一不留神被塞进 User::create() 就提权了。
- 安全底线:所有入库/传参操作,必须基于
validate()返回值或only(),绝不信任all()、except()或手动array_filter - 如果要用
FormRequest类,确保重写validated()而非all() - Laravel 9+ 支持
Validator::make(...)->validated(),和$request->validate()行为一致,适合非 HTTP 场景
only() 和 validate() 性能与语义差异
两者都能拿到子集,但动因和副作用不同:only() 是纯取值,不校验、不转换、不抛错;validate() 是完整校验流程,失败直接中断请求并返回 422。
容易忽略的是类型转换开销:比如 'price' => 'numeric|between:0,9999.99',validate() 会把 "199.99" 转成 float,而 only() 拿到的还是原始字符串 —— 这会影响后续计算或数据库写入精度。
- 需要强类型 + 安全过滤 → 无条件选
validate() - 只是临时取几个字段做日志或跳转参数 →
only()更轻量 - 不要混用:比如先
validate()再only(),可能因字段名不一致(如驼峰转下划线)导致取不到
API 场景下注意 Content-Type 影响
当请求是 application/json 时,$request->validate() 能正常工作;但如果是表单提交(application/x-www-form-urlencoded)且含数组嵌套(如 user[name]),only() 可能无法按预期提取嵌套键,而 validate() 仍可靠。
更隐蔽的问题:Nginx 或 CDN 可能默认 strip 掉某些 header,导致 Laravel 误判请求类型,validate() 解析 JSON 失败,报 "Unable to parse JSON data." 错误。
- 检查
$request->header('content-type')确认真实类型 - JSON 请求务必确保 header 里有
Content-Type: application/json - 调试时用
dd($request->all(), $request->validated())直接对比原始 vs 过滤后数据,比猜快得多
request()->all() 然后 array_merge 到模型创建参数里——只要有一个字段名对得上模型 fillable,就等于开了后门。白名单不是配置出来的,是每次取数时用代码强制执行的。


















