应使用FormRequest类而非$request->has()判断表单操作,因其能避免伪造提交、误判空值、逻辑膨胀等问题;多按钮需用name/value区分,验证规则须动态适配,数组字段命名须带[],且action字段必须在rules()中声明。

直接用 Request 对象或 FormRequest 类处理表单,而不是在控制器里手写 if-else 判断字段是否存在——这是最稳妥、可维护性最强的做法。
为什么不能靠 $request->has('delete') 判断按钮点击?
表面上看,给删除按钮加 name="delete",再在控制器里写 if ($request->has('delete')) 似乎能区分操作。但实际会踩几个坑:
- 如果用户禁用 JavaScript 后手动构造 POST 请求,
delete字段可能被伪造,而你没做权限校验就执行了删除 -
$request->has()只检查键是否存在,不区分是空字符串、"0"还是真实提交值,容易误判 - 多个按钮共用一个路由时,验证规则、中间件、日志记录都得围绕“操作类型”分支写,控制器迅速膨胀
- 后续加新操作(比如“导出”“冻结”)就得改一堆条件逻辑,而不是新增一个独立的验证类
FormRequest 类必须显式注入控制器方法
很多人写了 StoreUserRequest,rules() 也填好了,但表单一提交就跳过验证——根本原因是没把它真正“用上”:
- 控制器方法参数必须是
StoreUserRequest $request,不能是Request $request或request()辅助函数 -
authorize()方法默认返回false,不改成true或加权限判断,请求直接被拦截,连验证都不跑 - 一旦用了
FormRequest,就别再在方法体内调用$request->validate(),否则会绕过withValidator()、prepareForValidation()等钩子
正确写法示例:
public function update(UpdateUserRequest $request, User $user)
{
$user->update($request->validated());
return redirect()->back();
}
多操作表单要靠按钮的 name + value 区分,不是靠隐藏字段
同一个表单里放“保存”“删除”“发布”三个按钮,后端识别依据只能是被点击按钮本身的提交数据:
- 每个
<button type="submit">必须带name和value,例如:<button name="action" value="save">Save</button>、<button name="action" value="delete">Delete</button> - 控制器里用
$request->input('action')取值,比has()更准确(value是明确提交的字符串,不是存在性判断) - 验证规则可以按动作动态调整:在
FormRequest::rules()里用if ($this->action === 'delete') { ... }分支返回不同规则数组 - 注意 CSRF Token 仍需全局有效——所有按钮共享同一个表单,
@csrf写一次就够了,不用每个按钮重复
文件上传和数组字段命名必须带 [] 后缀
表单里要传多个文件或复选框组,HTML 层命名不规范会导致控制器收不到数组:
- 多文件上传的
<input type="file">必须写name="attachments[]",不能只写name="attachments",否则$request->file('attachments')返回单个文件或 null - 复选框组同理:
<input type="checkbox" name="roles[]" value="admin">,否则$request->input('roles')是字符串而非数组 - 在
FormRequest::rules()中,数组字段规则要用点号通配符:'attachments.*' => 'required|file|mimes:pdf,jpg',而不是'attachments' => 'array'就完事 - 验证失败时,
$errors会为每个数组项生成独立错误,前端可用$errors->has('attachments.0')精准提示
最常被忽略的一点:按钮的 name 值一旦用于路由分支判断,就必须出现在所有相关 FormRequest 的 rules() 中——哪怕只是 'action' => 'required|in:save,delete,publish',否则验证器会静默丢弃该字段,$request->input('action') 变成 null。


















