求助:如何在Django应用中实现单用户仅触发一次指定函数
Django实现同一用户无法重复触发耗时函数
问题分析
你当前的代码通过session标记来阻止重复触发,但存在几个关键问题:
- 同步阻塞的
sleep会导致请求长时间挂起,用户页面卡顿,且session修改可能因未及时保存,导致并发请求绕过检查 - GET请求易被重复提交或浏览器缓存,不符合"无副作用"的HTTP规范
- 前端无按钮禁用逻辑,用户可多次点击触发请求
解决方案
1. 后端逻辑优化(核心)
改用POST请求处理操作,结合session或缓存实现原子锁,确保同一用户无法重复触发:
修改后的views.py
from django.shortcuts import render from django.contrib.auth.decorators import login_required import time from django.http import JsonResponse from django.core.cache import cache @login_required(login_url="login") def page1(request): if request.method == "POST": # 用用户ID生成唯一锁键,高并发场景推荐用缓存原子锁 lock_key = f"nap_lock_{request.user.id}" # 原子设置锁,超时时间设为sleep总时长+1秒,避免异常导致死锁 if cache.add(lock_key, "locked", timeout=6): try: sleep(1, 5) finally: # 无论执行成功与否,都释放锁 cache.delete(lock_key) return JsonResponse({"status": "success", "msg": "操作完成"}) else: return JsonResponse({"status": "error", "msg": "你正在执行操作,请勿重复触发"}, status=400) return render(request, 'page1.html') def sleep(t, n): for i in range(n): time.sleep(t) print(f"nap n°{i}")
修改后的urls.py
from . import views from django.contrib.auth.decorators import login_required urlpatterns = [ path('page1', login_required(views.page1, login_url="login"), name="page1"), ]
2. 前端交互优化
点击按钮后立即禁用,防止用户重复点击,请求完成后恢复按钮状态:
修改后的page1.html
<button type="button" id="nap-btn">NAP</button> <script> const napBtn = document.getElementById('nap-btn'); napBtn.addEventListener('click', async () => { // 点击后禁用按钮并修改文本 napBtn.disabled = true; napBtn.textContent = '执行中...'; try { const response = await fetch("{% url 'page1' %}", { method: 'POST', headers: { 'X-CSRFToken': '{{ csrf_token }}', 'Content-Type': 'application/x-www-form-urlencoded', }, }); const result = await response.json(); alert(result.msg); } catch (error) { alert('请求出错,请稍后重试'); } finally { // 恢复按钮状态 napBtn.disabled = false; napBtn.textContent = 'NAP'; } }); </script>
方案说明
- 缓存原子锁:使用
cache.add()实现原子操作,比session更适合高并发场景,避免多个请求同时通过检查 - POST请求:符合HTTP规范,避免GET请求的缓存、重复提交问题
- 前端禁用:从交互层面直接阻止重复点击,提升用户体验
- 异常处理:通过
try-finally确保锁一定会被释放,避免死锁
内容的提问来源于stack exchange,提问作者problème0123
相关产品推荐
相关产品推荐

