第2.6章:数据验证
学习时间: 50 分钟
1. 验证:宇宙级防护盾
验证是指检查传入数据是否符合规则。没有它:
- 🚀 不正确的数据可能会“破坏”你的数据库
- 🌌 恶意攻击者可能会注入恶意代码
- 🪐 用户会收到难以理解的错误
💡 宇宙类比: 验证 = 空间站防御系统:
- 在对接前检查“货物”(数据)
- 拒绝危险物体
- 过滤太空碎片
2. 在 Laravel API 中何处进行验证
主要方法:
- 在控制器中 (快捷,但会使代码臃肿)
- 表单请求 (Form Request) (推荐,架构清晰)
3. 在控制器中进行验证
使用 Request 对象的 validate()
方法:
<?php
public function store(Request $request)
{
$validated = $request->validate([
'name' => 'required|string|max:255|unique:planets',
'description' => 'required|string',
'size_km' => 'required|integer|min:100|max:500000',
'solar_system' => 'required|string|max:100',
'image_url' => 'nullable|url|max:2048',
'is_habitable' => 'boolean'
]);
// ... 创建星球
}
常用验证规则:
规则 | 描述 | 示例 |
---|---|---|
required |
必填字段 | 'name' => 'required' |
string |
字符串值 | 'description' => 'string' |
integer |
整数 | 'size_km' => 'integer' |
min:value |
最小值/最小长度 | 'size_km' => 'min:100' |
max:value |
最大值/最大长度 | 'name' => 'max:255' |
unique:table,column |
表中唯一性 | 'name' => 'unique:planets' |
url |
有效 URL | 'image_url' => 'url' |
boolean |
true/false/1/0 | 'is_habitable' => 'boolean' |
4. 自定义错误消息
修改默认的错误文本:
<?php
$validated = $request->validate(
[
'name' => 'required|unique:planets',
'size_km' => 'min:1000'
],
[
'name.required' => '星球名称是必填的!',
'name.unique' => '目录中已存在同名星球',
'size_km.min' => '星球直径不能小于 1000 公里'
]
);
错误响应示例 (自动返回 422 Unprocessable Entity):
{
"message": "The given data was invalid.",
"errors": {
"name": ["目录中已存在同名星球"],
"size_km": ["星球直径不能小于 1000 公里"]
}
}
5. 创建表单请求 (Form Request)
对于复杂的验证,我们创建一个单独的类:
步骤 1:生成
步骤 2:编辑 app/Http/Requests/StorePlanetRequest.php
<?php
public function authorize()
{
return true; // 对于 API 通常为 true
}
public function rules()
{
return [
'name' => 'required|string|max:255|unique:planets',
'description' => 'required|string',
'size_km' => 'required|integer|min:100|max:500000',
'solar_system' => 'required|string|max:100',
'image_url' => 'nullable|url|max:2048',
'is_habitable' => 'boolean'
];
}
public function messages()
{
return [
'name.unique' => '同名星球已存在!',
'size_km.min' => '直径不能小于 100 公里'
];
}
步骤 3:在控制器中使用
<?php
use App\Http\Requests\StorePlanetRequest;
public function store(StorePlanetRequest $request)
{
// 数据已验证!
$validated = $request->validated();
$planet = Planet::create($validated);
return response()->json($planet, 201);
}
6. 自定义验证规则
我们将创建一个规则来检查星球名称的“合理性”。Laravel 的标准规则无法检查名称是否被“禁止”,所以我们将编写自己的逻辑。
步骤 1:生成规则
Laravel 提供了一个 Artisan 命令来创建规则类的“骨架”。在终端中执行它:
步骤 2:编辑 app/Rules/ValidPlanetName.php
打开创建的文件。其结构简单明了。我们的任务是在 validate
方法内部实现逻辑。
<?php
namespace App\Rules;
use Closure;
use Illuminate\Contracts\Validation\ValidationRule;
class ValidPlanetName implements ValidationRule
{
/**
* 运行验证规则。
*
* @param \Closure(string): \Illuminate\Translation\PotentiallyTranslatedString $fail
*/
public function validate(string $attribute, mixed $value, Closure $fail): void
{
// 我们的名称“黑名单”
$forbidden = ['Земля 2.0', 'Нибиру', 'Планета X'];
// 检查输入值是否在我们的列表中,
// 忽略大小写。
if (in_array(strtolower($value), array_map('strtolower', $forbidden))) {
// 如果验证未通过,调用 $fail 函数
// 并附上用户将看到的错误文本。
$fail('此星球名称禁止使用!');
}
}
}
步骤 3:在表单请求 (Form Request) 中使用
现在我们的自定义规则已准备就绪。我们可以在任何表单请求中引用它,只需创建一个我们的类的新实例即可。
打开 app/Http/Requests/StorePlanetRequest.php
并将 new ValidPlanetName
添加到 name
字段的规则数组中。
<?php
// app/Http/Requests/StorePlanetRequest.php
namespace App\Http\Requests;
use App\Rules\ValidPlanetName; // <-- 别忘了导入类
use Illuminate\Foundation\Http\FormRequest;
class StorePlanetRequest extends FormRequest
{
// ... (authorize 方法)
public function rules(): array
{
return [
'name' => [
'sometimes',
'string',
'max:255',
'unique:planets',
new ValidPlanetName, // <-- 这就是我们的自定义规则
],
'description' => 'sometimes|string',
'size_km' => 'sometimes|integer|min:100|max:500000',
'solar_system' => 'sometimes|string|max:100',
'image_url' => 'nullable|url|max:2048',
'is_habitable' => 'sometimes|boolean'
];
}
// ... (messages 方法)
}
name
字段应用所有规则,并在遇到 new ValidPlanetName
时执行我们的自定义逻辑。
7. 用于更新 (Update) 的验证
更新数据时的特点:
更新记录时,验证规则通常有所不同。主要的特点是唯一性检查,它应该忽略当前正在更新的记录。
步骤 1:为更新创建一个单独的表单请求 (Form Request)
步骤 2:编辑app/Http/Requests/UpdatePlanetRequest.php
<?php
use Illuminate\Validation\Rule;
public function authorize(): bool
{
return true;
}
public function rules(): array
{
$planet = $this->route('planet'); // 从路由中获取模型
return [
'name' => [
'sometimes', // 仅当字段存在于请求中时才进行验证
'required',
'string',
'max:255',
Rule::unique('planets')->ignore($planetId),
],
'description' => 'sometimes|required|string',
'size_km' => 'sometimes|required|integer|min:100|max:500000',
// ... 其他带有 'sometimes' 的字段
];
}
<?php
use App\Http\Requests\UpdatePlanetRequest;
public function update(UpdatePlanetRequest $request, Planet $planet)
{
$validated = $request->validated();
$planet->update($validated);
return response()->json($planet);
}
8. 在 Postman 中测试验证
场景 1:名称唯一性错误
POST /api/planets
{
"name": "Марс",
"description": "Красная планета, цель будующих колонизаций",
"size_km": 6779,
"solar_system": "Solar System",
"is_habitable": false
}
场景 2:直径不正确
预期响应:巩固知识的测验
🚀 章节总结:
您已为您的宇宙 API 建立了强大的保护系统:
- 🛡️ 基本和自定义验证规则
- 📝 可读的错误消息
- 🧩 Form Request 用于复杂场景
- ⚙️ 更新数据的唯一规则
您的宇宙现已受到保护! 接下来,我们将学习如何处理“宇宙事故”——服务器错误。
📌 检查:
- 创建用于更新行星的 Form Request
- 添加自定义名称验证规则
- 通过 Postman 测试错误
⚠️ 如果验证失败:
- 检查控制器中 Form Request 的引入
- 确保
authorize()
返回 true- 对于更新时的唯一性,请使用
Rule::unique