如何在DRF中强制执行POST幂等性?

时间:2017-06-01 22:25:41

标签: python django-rest-framework

我有一个使用Django Rest Framework的API,我希望防止重复的POST请求(本着Post Exactly Once (POE)的精神)。特别是,我试图处理的场景是:

  1. 客户端发送HTTP POST以创建对象。
  2. API后端创建对象并将其提交给数据库。
  3. 客户端失去网络连接。
  4. API后端尝试发回成功响应,但无法做到 所以既然客户丢失了网络。
  5. 客户永远不会获得成功"响应,所以假设 请求失败。客户端重试请求,创建副本 对象。
  6. 对此on the mailing list进行了一些讨论,但没有实现代码。人们现在如何解决这个问题?

1 个答案:

答案 0 :(得分:3)

我通过添加对X-Idempotency-Key http标头的支持来解决这个问题,该标头可以由客户端设置。然后,我使用自定义权限类检查非幂等请求:

class IsIdempotent(permissions.BasePermission):
    message = 'Duplicate request detected.'

    def has_permission(self, request, view):
        if request.method != 'POST':
            return True
        ival = request.META.get('HTTP_X_IDEMPOTENCY_KEY')
        if ival is None:
            return True
        ival = ival[:128]
        key = 'idemp-{}-{}'.format(request.user.pk, ival)
        is_idempotent = bool(cache.add(key, 'yes',
                                       settings.IDEMPOTENCY_TIMEOUT))
        if not is_idempotent:
            logger.info(u'Duplicate request (non-idempotent): %s', key)
        return is_idempotent

我可以像这样添加到我的观点中:

class MyViewSet(mixins.RetrieveModelMixin,
                mixins.UpdateModelMixin,
                mixins.ListModelMixin,
                viewsets.GenericViewSet):
    permission_classes = [permissions.IsAuthenticated,
                          IsIdempotent]