$errors是ViewErrorBag实例,需用first()、get()等方法安全取值;Web表单须经session和错误共享中间件,API请求不生成$errors。

直接用 $errors->first('field') 或 $errors->get('field') 就能取到对应字段的错误,但前提是请求走的是 Web 表单流程(含 CSRF、重定向回页),API 请求默认不生成 $errors 变量。
为什么 Blade 里 $errors 有时是空的
常见错误现象:表单提交后没显示错误,@if($errors->any()) 不触发——大概率是请求没进 Web 中间件栈,或者验证根本没执行。
- 确保表单包含
@csrf,否则$request->validate()会在 CSRF 验证阶段就抛出 419 异常,根本不会走到字段规则校验 - API 请求(如
application/json)不会把错误写入 session,也不会绑定$errors到视图,Blade 拿不到任何东西 - 手动调用
Validator::make(...)->validate()而非$request->validate()时,框架不会自动闪存错误,$errors仍为空 - 如果用了自定义中间件或跳过了
StartSession和ShareErrorsFromSession,$errors就不会被注入视图
$errors 是什么类型,怎么安全取值
$errors 是 Illuminate\Support\ViewErrorBag 实例,不是数组也不是普通对象,不能用 isset($errors['email']) 或 array_key_exists 判断。
- 查单个字段首个错误:
$errors->first('email'),返回字符串或空字符串(不是 null) - 查单个字段所有错误:
$errors->get('email'),返回字符串数组,可能为空数组 - 查是否有任意错误:
$errors->any(),返回布尔值,比count($errors) > 0安全 - 字段名含点号(如
user.email)时,$errors->first('user.email')可直接用,无需转义
动态数组字段(如 title[en])的错误键名怎么写
验证规则写 'title.*' => 'required',错误键名会变成 title.en、title.zh 这种格式,不是 title[en]。
- Blade 中不能写
@error('title[en]')—— 这会查不存在的键,永远不生效 - 正确写法是
@error('title.en')或动态拼接:@error('title.' . $lang->isocode) - 如果
$lang->isocode是变量,别用{{ }}插入到@error参数里,那是语法错误;必须用 PHP 字符串拼接 - 通配符消息映射(如
'title.*.required')只影响提示文案,不改变实际存储的键名
API 场景下根本别指望 $errors
API 不走 session、不重定向、不渲染 Blade,$errors 在这类请求里从不出现。强行在 JSON 响应里试图访问它,只会得到未定义变量警告。
- API 验证失败时,Laravel 默认返回
422 Unprocessable Entity+ JSON 格式错误体,结构为{"message":"...", "errors":{"email":["..."]}} - 要改这个结构,得重写
FormRequest::failedValidation()或全局捕获ValidationException,而不是动$errors - 前端接收时,直接读响应体里的
errors.email[0],别试图在 API 接口里 render 一个带$errors的 Blade 页面
最易被忽略的一点:错误键名和验证规则字段名严格一致,但和 HTML 的 name 属性不一定相同——比如 name="user[email]" 对应的验证字段名是 user.email,错误键也是 user.email,不是 user[email]。


















