Blazor 防止重复提交,核心思路是「禁用触发按钮 + 状态标记 + 异步操作防重入」,而不是靠后端拦截——因为用户点太快,前端没反应过来,请求已经发出去了。
按钮禁用 + Loading 状态
这是最直接有效的方式。在表单提交时立即将按钮设为 disabled,并显示 loading 提示,避免用户连续点击:
使用 @onclick 绑定事件,而非 @onsubmit(后者需手动 preventDefault) 用布尔变量(如 isSubmitting)控制按钮的 disabled 和 UI 文字 务必在 try/finally 中重置状态,确保异常时也能恢复按钮可用性 示例:<button @onclick="Submit" disabled="@isSubmitting">
@if (isSubmitting) { <span>提交中...</span> } else { <span>提交</span> }
</button>
@code {
private bool isSubmitting = false;
private async Task Submit()
{
if (isSubmitting) return;
isSubmitting = true;
try
{
await SaveDataAsync(); // 实际异步调用
}
finally
{
isSubmitting = false;
}
}
}
使用 CancellationToken 防止旧请求干扰
当用户快速多次点击,前一次请求还没结束,新请求就覆盖了上下文(比如编辑场景),可借助 CancellationTokenSource 主动取消上一次未完成的操作:
每次点击新建一个 CancellationTokenSource,保存引用 在发起 HTTP 或耗时操作时传入其 Token 新点击时先 Cancel() 上一个 source,再创建新的服务端幂等性兜底(推荐)
前端控制再严也存在绕过可能(比如 F5 刷新重发、调试工具重放)。建议后端配合实现幂等性:
客户端提交时附带唯一请求 ID(如 Guid.NewGuid().ToString()) 服务端用该 ID 做去重判断(缓存或数据库记录已处理的 ID,有效期建议 5–30 分钟) Blazor 调用 API 时,把 ID 放在 Header 或 Body 中传递避免表单原生 submit 导致页面刷新
如果用了 标签但没阻止默认行为,点回车或按钮可能触发两次(一次 JS 处理、一次浏览器原生提交):
要么去掉 ,纯用 button + @onclick 要么保留 form,但加 @onsubmit:preventDefault 并显式调用 event.PreventDefault() 别混用 type="submit" 和 @onclick —— 容易误触发基本上就这些。重点是前端禁用要即时、状态要可靠,后端幂等是安全底线。不复杂但容易忽略细节。
