如何使用Laravel验证器校验API请求参数?

2026-05-06 15:272阅读0评论SEO基础
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计878个文字,预计阅读时间需要4分钟。

如何使用Laravel验证器校验API请求参数?

很多人把验证逻辑写进+FormRequest+,但改着改着把+rules()+写成了+return [];+,或者条件不匹配导致返回空数组,结果请求请求完成不校验就进去了控制器——导致+422+。都不会触发异常。

  • 务必确保 rules() 至少返回一个非空数组,哪怕只是 ['id' => 'required|integer']
  • 如果想动态开关校验,用 withValidator() 做拦截,而不是清空 rules()
  • 测试时手动发个缺失必填字段的请求,看是否真返回 422 和错误信息,别只看代码有没有写 validate

Laravel 10+ 的 validated()safe()->all() 行为不同

validated() 返回的是经过规则过滤后的数据(比如你写了 'email' => 'required|email',它只返回 email 字段),而 safe()->all() 是把所有通过校验的字段全吐出来,包括没在 rules() 里声明的字段(只要没被 only() 限制)。

  • 如果你依赖 request->validated()['xxx'] 取值,但实际传了 xxx 却没写进 rules(),这里会报 Undefined array key
  • 想严格按规则取值,用 validated();想兼容额外参数(比如前端埋点字段),用 safe()->all() 并自己做字段白名单判断
  • safe() 在 Laravel 9.28+ 才稳定,低版本会抛 Method does not exist 错误

自定义错误消息写在 messages() 里,但中文键名要加引号

'title.required' => '标题不能为空' 没问题,但写成 title.required => '标题不能为空'(不加引号)会导致 PHP 解析失败,报 ParseError: syntax error

  • 所有含点号、中划线、中文的数组键名,必须用单引号或双引号包裹
  • 如果用了 trans() 做多语言,确保对应语言文件存在,否则显示空字符串,不是报错
  • 批量替换错误消息时,容易漏掉嵌套规则里的键名,比如 'tags.*.required' 这种通配写法也要加引号

API 验证失败默认返回 HTML 页面,不是 JSON

开箱即用的 FormRequest 在 API 路由里失败时,如果没显式指定响应格式,Laravel 仍可能返回重定向或 HTML 错误页,尤其当你混用了 webapi 中间件组。

  • 确认路由在 routes/api.php 里,并且没被 web 中间件污染(比如全局绑了 web
  • App\Exceptions\Handler.phprender() 方法里检查是否对 ValidationException 做了 JSON 包装,没做的话会走默认逻辑
  • 最简单兜底:在 FormRequest 里加 public function response(array $errors) { return response()->json($errors, 422); }
验证器本身不难,难的是那些“看起来跑通了,其实漏校验”或者“返回格式不对导致前端一直收不到错误”的隐性断点。尤其是跨版本升级后,safe()validated() 的边界容易模糊,上线前最好用 Postman 实测几个非法请求。
标签:Laravel

本文共计878个文字,预计阅读时间需要4分钟。

如何使用Laravel验证器校验API请求参数?

很多人把验证逻辑写进+FormRequest+,但改着改着把+rules()+写成了+return [];+,或者条件不匹配导致返回空数组,结果请求请求完成不校验就进去了控制器——导致+422+。都不会触发异常。

  • 务必确保 rules() 至少返回一个非空数组,哪怕只是 ['id' => 'required|integer']
  • 如果想动态开关校验,用 withValidator() 做拦截,而不是清空 rules()
  • 测试时手动发个缺失必填字段的请求,看是否真返回 422 和错误信息,别只看代码有没有写 validate

Laravel 10+ 的 validated()safe()->all() 行为不同

validated() 返回的是经过规则过滤后的数据(比如你写了 'email' => 'required|email',它只返回 email 字段),而 safe()->all() 是把所有通过校验的字段全吐出来,包括没在 rules() 里声明的字段(只要没被 only() 限制)。

  • 如果你依赖 request->validated()['xxx'] 取值,但实际传了 xxx 却没写进 rules(),这里会报 Undefined array key
  • 想严格按规则取值,用 validated();想兼容额外参数(比如前端埋点字段),用 safe()->all() 并自己做字段白名单判断
  • safe() 在 Laravel 9.28+ 才稳定,低版本会抛 Method does not exist 错误

自定义错误消息写在 messages() 里,但中文键名要加引号

'title.required' => '标题不能为空' 没问题,但写成 title.required => '标题不能为空'(不加引号)会导致 PHP 解析失败,报 ParseError: syntax error

  • 所有含点号、中划线、中文的数组键名,必须用单引号或双引号包裹
  • 如果用了 trans() 做多语言,确保对应语言文件存在,否则显示空字符串,不是报错
  • 批量替换错误消息时,容易漏掉嵌套规则里的键名,比如 'tags.*.required' 这种通配写法也要加引号

API 验证失败默认返回 HTML 页面,不是 JSON

开箱即用的 FormRequest 在 API 路由里失败时,如果没显式指定响应格式,Laravel 仍可能返回重定向或 HTML 错误页,尤其当你混用了 webapi 中间件组。

  • 确认路由在 routes/api.php 里,并且没被 web 中间件污染(比如全局绑了 web
  • App\Exceptions\Handler.phprender() 方法里检查是否对 ValidationException 做了 JSON 包装,没做的话会走默认逻辑
  • 最简单兜底:在 FormRequest 里加 public function response(array $errors) { return response()->json($errors, 422); }
验证器本身不难,难的是那些“看起来跑通了,其实漏校验”或者“返回格式不对导致前端一直收不到错误”的隐性断点。尤其是跨版本升级后,safe()validated() 的边界容易模糊,上线前最好用 Postman 实测几个非法请求。
标签:Laravel