防止 Django 中重复的 XMLHttpRequests

Preventing duplicate XMLHttpRequests in Django

在我的应用程序中,单击按钮会向我的服务器发送 XHR 请求以升级帐户并向用户收费。

def upgradeView(request):
    if request.user.upgraded == False:
         billAccount(request.user.id)
    else: 
         return HttpRequests('Already billed')
    request.user.upgraded = True
    request.user.save()
    return HttpResponse('OK!')

我可以使用 Javascript 更改按钮,以便在用户单击一次后将其禁用。我如何在服务器端确认用户不能同时提交 5 个 XHR 请求并最终被计费 5 次?我有一个手动检查,检查他们是否已经被计费,但是如果 billAccount 函数需要几秒钟,并且多个请求能够在用户被设置为升级之前触发 billAccount 调用怎么办?

越想越觉得防止多个请求滑入是不可能的。即使billAccount调用是一毫秒,也足以让多个请求滑入。

您可以添加另一个属性,该属性将在发送请求时设置为 True,然后在发送响应之前设置为 False。
根据该属性的值,您决定是否提出账单请求。

def upgradeView(request):
   if request.user.bill_state == 'open':
      # So there is a biliing request is running and we
   else:
      # set bill state to true to prevent any further requests
      request.user.bill_state = 'open'
      request.user.save()

   # make normal process of billing here an before end the request
   request.user.bill_state = 'close'
   request.user.save()

我认为将变量从 'open' 更改为 'close' 会比计费更快,而且您可以防止多次请求。

答案是使用 select_for_updatetransaction.atomic() 进行悲观锁定,以及“no_wait”参数。这样做是为了防止任何其他进程在该对象被锁定时选择该对象。 Here's 一个更深入的好资源。

以下是我认为您可以锁定该行以使多个事务不能同时发生的方法:

def upgradeView(request):
    with transaction.atomic():
        u = Users.objects.select_for_update(nowait=True).filter(pk=request.user.pk)
        if u.upgraded == False:
             billAccount(u.id)
        else: 
             return HttpRequests('Already billed')
        u.upgraded = True
        u.save()
        return HttpResponse('OK!')