使用 Request 类是 Laravel 最稳妥的表单验证方式,适用于字段超3个含条件校验、多方法复用规则、需权限控制或输入预处理的场景;通过 php artisan make:request 生成,重写 authorize()、rules()、messages() 方法,在控制器中类型提示即可自动验证。

直接用 Request 类做表单验证是 Laravel 最稳妥、最符合框架设计意图的方式——它把规则、消息、逻辑都收束在一处,比在控制器里写 $request->validate() 更易复用、更易测试、也更利于权限和前置逻辑控制。
什么时候必须用自定义 Request 类
不是所有表单都需要单独建 Request 类,但以下情况建议立刻拆出:
- 表单字段超过 3 个,且含条件校验(比如
required_if、required_unless) - 同一套规则被多个控制器方法复用(如
store和update都用到用户注册规则) - 需要在验证前做权限检查(例如只有管理员才能提交某字段)
- 需要对输入做预处理(如自动 trim、转小写、过滤 HTML)
如何生成和编写 Request 类
运行命令生成类:
php artisan make:request StorePostRequest生成的文件默认位于
app/Http/Requests/StorePostRequest.php。关键要改三个方法:
-
authorize():返回true允许继续,false直接 403;可在这里调$this->user()->can('create', Post::class) -
rules():返回关联数组,键为字段名,值为规则字符串或数组;支持required|string|min:3或['required', 'string', 'max:255'] -
messages()(可选):覆盖默认错误提示,键格式为"field.rule",如"title.required"→"标题不能为空"
示例:
public function rules()
{
return [
'title' => 'required|string|min:3|max:100',
'content' => 'required|string',
'category_id' => 'required|exists:categories,id',
'tags' => 'array',
'tags.*' => 'string|exists:tags,name',
];
}
Request 类怎么在控制器里用
不需要手动调 validate(),Laravel 会自动触发验证。只要把类型提示写对,框架就帮你拦住非法请求并返回 422:
- 在控制器方法参数中声明类型:
public function store(StorePostRequest $request) - 此时
$request->all()拿到的已是通过验证、且经过prepareForValidation()处理后的数据 - 若想在验证后统一处理字段(比如把
published_at空字符串转为null),重写prepareForValidation()方法即可
注意:如果控制器方法有中间件(如 auth:sanctum),Request 的 authorize() 会在中间件之后执行;顺序不可颠倒。
常见坑和性能注意点
Request 类不是万能胶,几个容易踩的点:
- 规则里写
exists:users,email却没加索引 → 数据量大时验证极慢,务必确保被查字段有数据库索引 - 在
rules()中动态拼接规则(如'price' => 'required|numeric|min:'.$this->user->min_price)→ 若$this->user为 null 会报错,应先判空或改用闭包规则 - 忘记在
authorize()返回布尔值(比如只写了$this->user()->can(...)但没return)→ 默认返回null,等价于false,导致所有请求被拒 -
前端传了
id字段,后端规则写了id' => 'required|exists:posts,id',但更新时该id实际来自路由参数(如post/{post})→ 应该验证路由模型绑定,而不是重复查库
复杂业务里,Request 类很容易变成“什么都往里塞”的地方。真正该放进去的,只有和当前 HTTP 请求强相关的验证与预处理逻辑;领域规则、状态流转、事务操作,依然属于控制器或服务类的职责。










