什么是校验
校验(Validation)指的是验证用户提交的数据是否符合预期的格式与条件。
Laravel 通过请求对象的 validate 方法,以及专用的 Form Request 类,提供了简洁而强大的校验能力。
在控制器中做校验
$request->validate() 的用法
在控制器方法中调用 $request->validate() 是最直接的校验方式。
校验失败时,Laravel 会自动把用户重定向回前一页,并把错误信息存入 Session。
定义路由:
use App\Http\Controllers\PostController;
Route::get('/post/create', [PostController::class, 'create']);
Route::post('/post', [PostController::class, 'store']);
编写控制器:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\View\View;
class PostController extends Controller
{
public function create(): View
{
return view('post.create');
}
public function store(Request $request): RedirectResponse
{
$validated = $request->validate([
'title' => 'required|string|max:255',
'body' => 'required|string',
'email' => 'required|email',
]);
// 使用校验后的数据保存文章...
return redirect('/posts');
}
}
validate 接收以字段名为键、规则为值的数组。
规则可以用 | 分隔或使用数组。
// 用竖线分隔
'title' => 'required|string|max:255',
// 数组
'title' => ['required', 'string', 'max:255'],
主要校验规则
| 规则 | 说明 |
|---|
required | 值必须存在且非空 |
string | 必须是字符串 |
email | 必须是合法邮箱格式 |
min:值 | 字符串长度或数值不少于指定值 |
max:值 | 字符串长度或数值不超过指定值 |
unique:表 | 在指定表中值唯一 |
nullable | 允许 null |
integer | 必须是整数 |
boolean | 布尔值(true/false、1/0 等) |
date | 有效的日期格式 |
confirmed | 与 字段名_confirmation 字段一致 |
使用校验后的数据
validate 的返回值是只包含通过校验字段的数组,可作为可信数据使用。
$validated = $request->validate([
'title' => 'required|string|max:255',
'body' => 'required|string',
]);
Post::create($validated);
Blade 中展示错误
校验失败时,Laravel 会让所有视图都能自动访问 $errors 变量。
这由 web 中间件组中的 ShareErrorsFromSession 中间件负责。
列出全部错误
@if ($errors->any())
<ul>
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
@endif
按字段展示错误
使用 @error 指令可在字段旁行内显示错误:
<label for="title">标题</label>
<input
id="title"
type="text"
name="title"
value="{{ old('title') }}"
class="@error('title') is-invalid @enderror"
/>
@error('title')
<div class="error-message">{{ $message }}</div>
@enderror
使用 old('字段名') 可在校验失败后仍将用户输入的值填回表单。
当校验逻辑较复杂时,可将其抽离到「Form Request」类中。
Form Request 将校验与授权逻辑集中到一个自定义请求类中。
用 make:request Artisan 命令生成:
php artisan make:request StorePostRequest
会生成 app/Http/Requests/StorePostRequest.php:
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class StorePostRequest extends FormRequest
{
/**
* 判断是否有权限执行此请求
*/
public function authorize(): bool
{
return true;
}
/**
* 返回应用到此请求的校验规则
*/
public function rules(): array
{
return [
'title' => 'required|string|max:255',
'body' => 'required|string',
'email' => 'required|email|unique:posts',
];
}
}
rules() 方法
以数组形式返回校验规则,与直接传给 validate 的一致。
authorize() 方法
判断是否有权限执行该请求。
返回 true 通过,返回 false 时自动返回 403。
若只允许已认证用户,可用 auth()->check()。
教程中直接返回 true 即可。
当 authorize 返回 false 时,控制器方法不会执行,会直接返回 403 Forbidden。
注入到控制器
只需在控制器方法上做类型提示即可使用 Form Request。
控制器执行前会先运行校验,因此无需在方法内再写校验代码。
use App\Http\Requests\StorePostRequest;
class PostController extends Controller
{
public function store(StorePostRequest $request): RedirectResponse
{
// 到达此处即校验通过
$validated = $request->validated();
Post::create($validated);
return redirect('/posts');
}
}
$request->validated() 只返回校验过的数据。
实践示例:创建并保存投稿表单
以下是从展示表单到提交、校验、保存的完整流程:
定义路由
use App\Http\Controllers\PostController;
Route::get('/posts/create', [PostController::class, 'create']);
Route::post('/posts', [PostController::class, 'store']);
生成 Form Request
php artisan make:request StorePostRequest
public function rules(): array
{
return [
'title' => 'required|string|max:255',
'body' => 'required|string',
];
}
public function authorize(): bool
{
return true;
}
实现控制器
use App\Http\Requests\StorePostRequest;
use App\Models\Post;
class PostController extends Controller
{
public function create(): View
{
return view('posts.create');
}
public function store(StorePostRequest $request): RedirectResponse
{
Post::create($request->validated());
return redirect('/posts');
}
}
创建 Blade 模板
{{-- resources/views/posts/create.blade.php --}}
<h1>新建文章</h1>
@if ($errors->any())
<ul>
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
@endif
<form method="POST" action="/posts">
@csrf
<div>
<label for="title">标题</label>
<input
id="title"
type="text"
name="title"
value="{{ old('title') }}"
/>
@error('title')
<span>{{ $message }}</span>
@enderror
</div>
<div>
<label for="body">正文</label>
<textarea id="body" name="body">{{ old('body') }}</textarea>
@error('body')
<span>{{ $message }}</span>
@enderror
</div>
<button type="submit">发表</button>
</form>
Blade 表单请务必包含 @csrf 指令,否则 Laravel 会返回 419 错误。
下一步