laravel中web与api需按请求类型区分验证路径和响应格式:web用validate()+重定向+$errors渲染,api须走api中间件以返回422 json响应,formrequest可复用规则但错误呈现必须隔离。

不需要硬性分开,但必须按请求类型区分验证逻辑的执行路径和响应格式。
Web页面提交用 validate() + 重定向错误
表单走传统 HTML POST,Laravel 默认会把验证失败的错误存入 session,然后重定向回原页面,并通过 $errors 变量在 Blade 中渲染。这个流程依赖 Laravel 的 session 和 redirect 机制,对 API 完全不适用。
- 控制器里直接调用
$request->validate()即可,不用 try-catch - 错误响应是 302 重定向 + session 存储,前端收不到 JSON 错误体
- 如果在 Web 路由里强行返回 JSON(比如加了
Accept: application/json),Laravel 仍会抛出ValidationException,但默认异常处理器会转成 422 响应——这容易和 API 场景混淆,需留意
API 请求必须用 FormRequest 或手动捕获 ValidationException
前后端分离或移动端调用时,客户端只认 JSON 响应。Laravel 的 validate() 在 API 路由中也会抛 ValidationException,但默认异常处理器会统一转为 422 + JSON 格式,前提是路由已绑定 api 中间件(它会触发 App\Exceptions\Handler::render() 中的 JSON 分支)。
- 推荐用
FormRequest类:把规则、消息、authorize()全部封装,控制器方法签名更干净 - 若用
$request->validate(),确保该路由在routes/api.php或显式加了middleware('api'),否则可能返回 HTML 错误页 - 不要在 API 方法里写
try/catch包裹$request->validate()—— 这会吞掉 Laravel 自动处理的 422 响应,导致前端收不到标准错误结构
同一个验证规则可以复用,但不能共用同一套响应逻辑
字段规则如 'email' => 'required|email|unique:users' 完全可以在 Web 和 API 的 FormRequest 中复用,但错误渲染方式必须隔离:
- Web 场景下,
messages()仅用于生成$errors对象供 Blade 使用 - API 场景下,
errors()输出的是关联数组,被自动包装进errors键的 JSON 响应体 - 自定义错误消息数组(如
['email.required' => '邮箱不能为空'])可共用,但要注意 Web 模式下 key 是点号分隔,API 模式下最终结构是嵌套数组,key 不影响实际使用
容易踩的坑:混用中间件和响应预期
最常见问题是把 API 接口注册在 web 路由文件里,或者忘了给 API 控制器加 api 中间件。结果就是验证失败时返回 HTML 页面或空白响应,而不是 {"message":"The given data was invalid.","errors":{...}}。
- 检查路由是否在
routes/api.php,或是否显式绑定了middleware('api') - 不要在
web路由中返回 JSON 响应来“模拟 API”,session 和 CSRF 机制会让这种混合模式极难调试 -
FormRequest的authorize()方法返回false时,Laravel 抛的是AuthorizationException,不是ValidationException,状态码是 403,这点常被忽略
真正需要隔离的不是“参数验证本身”,而是错误如何呈现、由谁消费。规则可以共享,通道决定格式,中间件决定行为——漏掉任一环,验证就变成黑盒调试。











