Skip to content

防重复提交

防重复提交是保障数据一致性的重要措施。通过前端防抖和后端唯一性校验双重保护,防止用户重复点击导致的数据重复提交。后端唯一性校验通过 WTForms 自定义校验器查询数据库实现。

前端防抖 ​

useLockFn ​

前端提供 useLockFn 钩子函数,实现请求级别的防重复提交:

javascript
import { useLockFn } from '@/utils/useLockFn'

// 包装提交函数,防止重复点击
const { lockFn: handleSubmit } = useLockFn(async () => {
    await axios.post('/api/v1/level/add', formData)
    ElMessage.success('添加成功')
})

useLockFn 原理:

javascript
import { ref } from 'vue'

export function useLockFn(fn) {
    const isLock = ref(false)
    const lockFn = async (...args) => {
        if (isLock.value) return
        isLock.value = true
        try {
            await fn(...args)
        } finally {
            isLock.value = false
        }
    }
    return { isLock, lockFn }
}

按钮 loading ​

ElementPlus 的按钮组件支持 loading 属性,请求期间禁用按钮:

vue
<el-button
    type="primary"
    :loading="submitting"
    @click="handleSubmit"
>
    提交
</el-button>

<script setup>
const submitting = ref(false)

async function handleSubmit() {
    submitting.value = true
    try {
        await axios.post('/api/v1/level/add', formData)
        ElMessage.success('添加成功')
    } finally {
        submitting.value = false
    }
}
</script>

后端幂等性 ​

唯一性约束 ​

通过数据库唯一索引和 WTForms 验证器保证数据唯一性:

python
from wtforms import StringField
from wtforms.validators import DataRequired, Length, ValidationError

class LevelForm(BaseForm):
    name = StringField('职级名称', validators=[
        DataRequired(message='职级名称不能为空'),
        Length(min=1, max=150, message='职级名称长度必须在1-150个字符之间')
    ])

    def validate_name(self, field):
        # 查询数据库校验唯一性
        exclude_id = self.id.data if self.id.data else None
        if LevelRepository.exists_by([Level.name == field.data], exclude_id):
            raise ValidationError('职级名称已存在')

软删除 + 唯一索引 ​

软删除场景下,唯一索引需要特殊处理:

sql
-- MySQL: 唯一索引包含 is_delete 字段
ALTER TABLE flask_level ADD UNIQUE INDEX uk_name (name, is_delete);

-- PostgreSQL: 部分唯一索引
CREATE UNIQUE INDEX uk_name ON flask_level (name) WHERE is_delete = 0;

最佳实践 ​

1. 前端防抖:useLockFn 或按钮 loading,防止用户重复点击
2. 后端校验:WTForms 验证器 + 数据库唯一索引,双重保障
3. 幂等设计:相同请求多次执行结果一致
4. 错误提示:重复提交时返回明确的错误提示

总结 ​

防重复提交方案具备以下特点:

1. 前端防抖:useLockFn 函数级防抖,按钮 loading 状态控制
2. 后端校验:WTForms 验证器查询数据库校验唯一性
3. 数据库约束:唯一索引兜底,防止并发重复插入
4. 双重保护:前端防抖 + 后端校验,确保数据一致性
5. 用户体验:重复点击时按钮禁用,返回明确提示

小蚂蚁云团队 · 提供技术支持