ThinkPHP防重复提交核心是服务端一次性Token+Session绑定+立即销毁闭环。需显式生成Token并嵌入表单,提交时严格校验并立即清除Session中Token,成功后必须重定向跳转,前端禁用按钮仅为体验优化。
ThinkPHP 防重复提交不能只靠前端禁用按钮或数据库唯一索引,核心是「服务端一次性 Token + Session 绑定 + 立即销毁」的闭环。Token 必须生成、嵌入、校验、清空四步到位,缺一不可。
表单页:正确生成并嵌入 Token
Token 不是配置打开就自动生效,必须显式生成并写入表单。ThinkPHP 6.x 推荐两种方式:
使用内置模板标签:
(V6.1+ 默认不启用,需在
中设
);
手动控制更稳妥:控制器中调用
,再存入 Session:
;
模板中写成:
,字段名保持与后端校验一致。
提交时:严格校验并立即销毁
Token 校验不是可选步骤,而是业务逻辑执行前的第一道闸门:
必须用
严格比对,避免类型转换绕过(如
);
校验通过后第一件事是
或
,不是赋空字符串或留着不管;
若用验证器,
字段默认不进
,需单独提取:
,否则规则不触发;
更推荐启用中间件
,并在路由中注册,由框架统一拦截非法请求。
跳转后:防止刷新重发 POST 请求
用户提交成功后按 F5 刷新,浏览器会重发原始 POST —— 这是 PRG(Post-Redirect-Get)没做完整的表现:
PHP 8.5.5
PHP 8.5.5 是 PHP 8.5 分支的维护更新版本。该版本延续了“小步快跑”的迭代逻辑,通过深度错误修复、底层性能微调以及安全加固,旨在为开发者提供一个更健壮、更高效的运行环境。该版本严格遵守语义化版本规范,不包含破坏性变更。
下载
立即学习
“
PHP免费学习笔记(深入)
”;
控制器处理完必须用
跳转,不能直接
返回当前页;
前端可辅助增强:跳转后执行
,把表单页从历史栈中替换掉;
表单页加载时检测是否为刷新进入:
,清空表单并禁用按钮。
前端配合:禁用按钮只是体验优化,不是防重主力
按钮禁用能减少误点,但绕过 JS 极其容易,绝不能替代后端校验:
用
统一入口;
禁用同时改文案为「提交中…」,避免用户因无反馈而狂点;
AJAX 提交务必在
中恢复按钮状态,不能只在
或
里处理;
不要用
这类粗暴写法,它不响应回车提交和屏幕阅读器等辅助操作。
{__token__/}config/app.php'token_on' => true$this->assign('token', Str::random(32))session('submit_token', $token)==="0" == falsesession('submit_token', null)session()->delete('submit_token')__token$data$data['__token'] = $this->request->param('__token')think\middleware\Tokenreturn redirect('/success')return $this->fetch()history.replaceState({}, '', location.href)if (performance.navigation?.type === 1) { document.querySelector('form').reset(); }form.addEventListener('submit', e => { e.preventDefault(); btn.disabled = true; ... })finallythencatchonclick="return false"