laravel 的 $request->validate() 默认抛异常而非返回错误数组,因其设计为“失败即中断”,便于 blade 自动绑定 $errors;api 场景应改用 validator::make() 或统一在 handler::render() 中处理 validationexception。

验证失败时为什么 $request->validate() 直接抛异常而不是返回错误数组?
因为 Laravel 默认在表单请求或控制器中调用 $request->validate() 时,底层走的是 ValidateIfs::validate() + 异常处理器流程,不是单纯返回结果。它设计初衷就是「失败即中断」,方便配合 Blade 的 $errors 自动绑定。
- 想手动获取错误信息?改用
$validator = Validator::make($data, $rules);,再调$validator->fails()和$validator->errors() - API 场景别硬套
$request->validate(),否则 422 响应体结构和前端预期不一致(默认带 HTML 错误模板) - 自定义异常响应格式?重写
App\Exceptions\Handler::render()中对ValidationException的处理分支
写自定义规则时,passes() 返回 false 却没显示错误信息?
常见于忘记在 message() 方法里返回字符串,或者返回了空字符串、null。Laravel 只有在 message() 有非空返回时,才把该规则加入错误列表。
- 必须实现
message(),且返回值是string,例如:return '手机号格式不正确'; - 不要在
passes()里 throw Exception —— 这会绕过验证流程,导致错误不进$errors - 如果规则逻辑复杂需提前退出,用
return false;+ 正确的message(),别试图“手动触发报错”
在 API 路由里用 FormRequest 验证,为什么 failedValidation() 不生效?
因为 Laravel 默认对 API 请求(Accept: application/json 或路由在 api 中间件组)会跳过 FormRequest::failedValidation(),直接走全局异常处理器返回 JSON。
- 强制走自定义逻辑?在
FormRequest中重写expectsJson()并返回false - 更稳妥的做法:不在
FormRequest里重写failedValidation(),而是统一在Handler::render()拦截ValidationException,按需返回 JSON 或重定向 - 注意中间件顺序:
SubstituteBindings要在验证前执行,否则路由参数未解析可能导致规则取值为空
Rule::unique() 在更新场景漏判自己那条记录?
这是最常踩的坑:Rule::unique('users', 'email') 默认查全表,更新用户 A 时如果邮箱没变,它会把 A 自己也当冲突报错。
- 必须加忽略条件:
Rule::unique('users', 'email')->ignore($user->id) - 如果主键不是
id,要显式传字段名:->ignore($user->id, 'user_id') - 软删除模型要注意:默认
unique不排除deleted_at IS NOT NULL,需手动加whereNull('deleted_at')
ignore() 参数没传对、message() 返回空、以及 API/WEB 路由混用同一套 FormRequest 这三类,线上出问题时根本不会报错,只会静默失效。











