Laravel框架内置的请求对象功能十分强大,除了可以获取用户提交的请求数据,还支持将校验逻辑、授权逻辑封装到独立的请求类中,避免控制器中出现大量重复的校验代码,让整体代码结构更清晰。

基础请求对象的使用
默认情况下,我们可以在控制器方法中直接注入IlluminateHttpRequest对象来获取请求数据,基础的校验可以通过validate方法实现:
<?php
namespace AppHttpControllers;
use IlluminateHttpRequest;
class UserController extends Controller
{
public function store(Request $request)
{
// 基础校验逻辑
$validated = $request->validate([
'name' => 'required|string|max:20',
'email' => 'required|email|unique:users',
'password' => 'required|string|min:8|confirmed',
], [
'name.required' => '用户名不能为空',
'email.unique' => '该邮箱已被注册',
'password.min' => '密码长度不能小于8位',
]);
// 校验通过后的业务逻辑
// ...
}
}
这种方式适合简单场景,但如果多个接口都需要相同的校验规则,就需要重复编写校验代码,此时封装自定义请求类就是更好的选择。
自定义请求类封装校验逻辑
Laravel提供了make:request命令可以快速生成自定义请求类,生成的类默认存放在app/Http/Requests目录下。
生成请求类
执行以下命令生成用户注册的请求类:
php artisan make:request RegisterUserRequest
配置校验规则与错误提示
打开生成的RegisterUserRequest.php文件,我们可以看到两个核心方法:authorize和rules,还可以添加messages方法自定义错误提示。
<?php
namespace AppHttpRequests;
use IlluminateFoundationHttpFormRequest;
class RegisterUserRequest extends FormRequest
{
/**
* 判断是否有权限执行该请求对应的操作
* 返回true表示允许,返回false会抛出403错误
*/
public function authorize()
{
// 注册接口一般不需要额外授权,直接返回true
return true;
}
/**
* 定义校验规则
*/
public function rules()
{
return [
'name' => 'required|string|max:20',
'email' => 'required|email|unique:users',
'password' => 'required|string|min:8|confirmed',
];
}
/**
* 自定义错误提示信息
*/
public function messages()
{
return [
'name.required' => '用户名不能为空',
'name.max' => '用户名长度不能超过20个字符',
'email.required' => '邮箱不能为空',
'email.email' => '邮箱格式不正确',
'email.unique' => '该邮箱已被注册',
'password.required' => '密码不能为空',
'password.min' => '密码长度不能小于8位',
'password.confirmed' => '两次输入的密码不一致',
];
}
}
在控制器中使用自定义请求类
将原来的Request对象替换为自定义的RegisterUserRequest,此时框架会自动执行校验逻辑,校验不通过会直接返回对应的错误响应,不需要手动调用validate方法。
<?php
namespace AppHttpControllers;
use AppHttpRequestsRegisterUserRequest;
class UserController extends Controller
{
public function store(RegisterUserRequest $request)
{
// 这里可以直接获取校验通过后的数据,不需要额外处理校验逻辑
$validatedData = $request->validated();
// 执行用户注册的业务逻辑
// ...
}
}
进阶封装技巧
复用校验规则
如果多个请求类需要用到相同的校验规则,可以把公共规则提取到基类中,其他请求类继承基类即可。
<?php
namespace AppHttpRequests;
use IlluminateFoundationHttpFormRequest;
class BaseRequest extends FormRequest
{
// 公共的邮箱校验规则
protected function emailRules()
{
return ['required', 'email', 'unique:users'];
}
}
然后让RegisterUserRequest继承BaseRequest:
<?php
namespace AppHttpRequests;
class RegisterUserRequest extends BaseRequest
{
public function authorize()
{
return true;
}
public function rules()
{
return [
'name' => 'required|string|max:20',
'email' => $this->emailRules(),
'password' => 'required|string|min:8|confirmed',
];
}
public function messages()
{
return [
'name.required' => '用户名不能为空',
'name.max' => '用户名长度不能超过20个字符',
'email.required' => '邮箱不能为空',
'email.email' => '邮箱格式不正确',
'email.unique' => '该邮箱已被注册',
'password.required' => '密码不能为空',
'password.min' => '密码长度不能小于8位',
'password.confirmed' => '两次输入的密码不一致',
];
}
}
自定义校验规则
如果遇到框架内置校验规则无法满足的场景,可以在请求类中添加自定义校验规则,比如校验手机号格式:
<?php
namespace AppHttpRequests;
use IlluminateFoundationHttpFormRequest;
use IlluminateValidationRule;
class RegisterUserRequest extends FormRequest
{
public function authorize()
{
return true;
}
public function rules()
{
return [
'name' => 'required|string|max:20',
'email' => 'required|email|unique:users',
'password' => 'required|string|min:8|confirmed',
'phone' => [
'required',
'string',
// 自定义手机号校验规则
function ($attribute, $value, $fail) {
if (!preg_match('/^1[3-9]d{9}$/', $value)) {
$fail('手机号格式不正确');
}
},
],
];
}
public function messages()
{
return [
'name.required' => '用户名不能为空',
'phone.required' => '手机号不能为空',
// 其他提示信息省略
];
}
}
根据请求场景调整规则
如果是更新用户信息接口,邮箱的唯一校验需要排除当前用户,此时可以通过route方法获取路由参数,动态调整校验规则:
<?php
namespace AppHttpRequests;
use IlluminateFoundationHttpFormRequest;
class UpdateUserRequest extends FormRequest
{
public function authorize()
{
return true;
}
public function rules()
{
$userId = $this->route('user');
return [
'name' => 'sometimes|string|max:20',
'email' => [
'sometimes',
'email',
// 更新时排除当前用户的邮箱唯一校验
Rule::unique('users')->ignore($userId),
],
'password' => 'sometimes|string|min:8|confirmed',
];
}
}
这里使用sometimes规则表示只有请求中包含该字段时才进行校验,适合更新场景下的部分字段校验需求。
总结
通过封装Laravel请求对象,我们可以将校验规则、错误提示、授权逻辑统一收敛到独立的请求类中,不仅减少了控制器中的重复代码,也让校验逻辑更易于维护和扩展。在实际开发中,可以根据业务需求灵活使用复用规则、自定义规则、场景化规则等技巧,让请求封装更贴合项目实际场景,提升整体开发效率。