You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flask表单如何避免用户快速点击提交按钮导致重复提交?

解决Flask表单重复提交问题

为什么重定向仍无法阻止快速点击的重复提交?

Post/Redirect/Get(PRG)模式确实能解决用户刷新页面导致的重复提交,但无法处理用户在短时间内快速点击提交按钮的场景——因为多个POST请求会在第一次请求完成重定向之前就已发送到服务器。第一次提交成功写入数据库后,后续请求会因用户名/邮箱重复被验证拦截,但仍会触发服务端请求。

可行解决方案

1. 客户端:智能控制按钮状态

不点击就禁用,而是仅在表单前端验证通过后禁用按钮,验证失败时自动恢复可用状态。在register.html的{% endblock %}前添加以下脚本:

<script>
const form = document.querySelector('form');
const submitBtn = document.getElementById('submit-button');

form.addEventListener('submit', function(e) {
    // 检查页面是否存在Flask-WTF返回的验证错误
    const hasServerErrors = document.querySelectorAll('[style="color: red"]').length > 0;
    if (!hasServerErrors) {
        submitBtn.disabled = true;
        submitBtn.textContent = '提交中...';
    }
});

// 页面加载时,若存在验证错误则确保按钮可用
window.addEventListener('load', function() {
    const hasServerErrors = document.querySelectorAll('[style="color: red"]').length > 0;
    if (hasServerErrors) {
        submitBtn.disabled = false;
        submitBtn.textContent = 'Submit';
    }
});
</script>

2. 服务端:失效当前CSRF令牌

利用Flask-WTF的CSRF机制,在表单提交成功后刷新令牌,让重复提交的旧令牌失效。修改app.py:

from flask_wtf.csrf import generate_csrf

@app.route("/register", methods=['GET','POST'])
def register():
  form = RegisterForm()

  if form.validate_on_submit():
    hashed_password = bcrypt.generate_password_hash(form.password.data)
    new_user = User(username=form.username.data, email=form.email.data.lower(), password=hashed_password)
    db.session.add(new_user)
    db.session.commit()
    # 刷新CSRF令牌,使旧令牌失效
    generate_csrf()
    return redirect(url_for('login'))
  else:
    print(form.errors.items())
  
  return render_template("register.html", form=form)

3. 数据库:添加唯一约束

作为最后一道防线,确保即使服务端验证失效,数据库也不会写入重复数据。修改User模型:

from sqlalchemy import UniqueConstraint

class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(20), nullable=False)
    email = db.Column(db.String(120), nullable=False)
    password = db.Column(db.String(60), nullable=False)
    
    # 添加用户名和邮箱的唯一约束
    __table_args__ = (
        UniqueConstraint('username', name='unique_username'),
        UniqueConstraint('email', name='unique_email'),
    )

内容的提问来源于stack exchange,提问作者Cristian Cassetta

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 06:50:26