Laravel+Vue防止重复提交表单
后端:使用 Redis 分布式锁
在处理表单提交的控制器方法中,可以使用 Cache::lock 方法来实现一个简单的锁机制。下面是一个示例代码:
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Log;
public function submitOrder(Request $request)
{
// 锁的键名,这里可以根据用户ID和场景自定义,确保唯一性
$lockKey = 'order_submit_lock_' . auth()->id();
// 尝试获取锁,$seconds是锁的有效期,这里设置为5秒
$lock = Cache::lock($lockKey, 5);
// 如果无法获取锁,说明有其他请求正在处理,直接返回错误
if (!$lock->get()) {
return response()->json(['message' => '请勿重复提交订单'], 429);
}
try {
// 在这里执行你的业务逻辑,比如保存订单到数据库
// ...
// 业务逻辑处理成功后,可以手动释放锁,但在 Laravel 中通常不需要显式释放,
// 因为锁会自动在给定的有效期后释放,或者在脚本结束时(如果设置了自动释放)
} catch (\Exception $e) {
// 记录异常,根据需要处理
Log::error('提交订单时发生错误: ' . $e->getMessage());
// 如果在 catch 块内,确保抛出异常前解锁,以防锁未被正确释放
$lock->release();
throw $e; // 再次抛出异常,让全局异常处理器处理
}
// 成功响应
return response()->json(['message' => '订单提交成功'], 200);
}
注意事项
上述示例中,Cache::lock 会尝试获取一个分布式锁。如果锁已经被持有,则该方法会立即返回 false,避免了重复处理。
锁的有效期(上述示例中的5秒)应该根据你的业务需求调整,确保它足够长以覆盖正常的处理时间,但也不要过长,以免长时间阻塞其他请求。
Laravel 的 Redis 锁实现了自动释放机制,一般情况下不需要手动调用 release() 方法,除非你在特定的异常处理流程中需要提前释放锁。
当使用锁时,要考虑死锁的可能性,确保锁的有效期合理,并且在逻辑处理完成后能正常结束,避免锁永远不被释放的情况。
前端:(vue)
在Vue组件中,当表单提交按钮被点击时,立即将按钮设置为disabled状态,防止再次点击。
创建一个自定义Vue指令来全局处理按钮的重复点击问题,如以下示例:
Vue.directive('prevent-repeated-submit', {
// 当绑定元素插入到DOM中时...
inserted(el) {
// 添加点击事件监听器
el.addEventListener('click', () => {
// 检查按钮是否已经被禁用,避免重复触发
if (el.disabled) return;
// 设置loading和disabled属性为true
el.loading = true;
el.disabled = true;
});
}
});
然后在模板中使用该指令:
<button ref="submitBtn" v-prevent-repeated-submit @click="submitForm">提交订单</button>
提交完成后需要恢复loading和disabled状态
methods: {
submitForm() {
this.$refs.myForm.validate((valid) => {
if (valid) {
axios.post('/api/order', this.formData)
.then(() => {
// 操作成功的处理...
})
.finally(() => {
// 无论成功或失败,在异步操作完成后重置按钮状态
this.$nextTick(() => {
this.$refs.submitBtn.loading = false;
this.$refs.submitBtn.disabled = false;
});
});
}
});
}
}
使用this.$nextTick确保在DOM更新完成后再修改loading和disabled状态。
本文是原创文章,采用 CC BY-NC-ND 4.0 协议,完整转载请注明来自 从前从前 Bolg