Django rest fram中的自定义节流响应

2024-10-01 13:39:26 发布

您现在位置:Python中文网/ 问答频道 /正文

我将DRF用于restapi,所以现在我对api应用了节流。为此,我创建了以下节流范围

  1. 用户速率限制

  2. 自动油门

  3. 紧急油门

  4. perViewsThrottles(视情况而定)

目前我得到以下回复:

{"detail":"Request was throttled. Expected available in 32.0 seconds."}

我想要这样的回应:

{"message":"request limit exceeded","availableIn":"32.0 seconds","throttleType":"type"}

DRF文档中没有可供定制的内容。如何根据要求定制我的响应?在


Tags: 用户apirestapi速率request情况drfexpected
3条回答

为此,您可以实现一个custom exception handler function,在^{}异常情况下返回自定义响应。在

from rest_framework.views import exception_handler
from rest_framework.exceptions import Throttled

def custom_exception_handler(exc, context):
    # Call REST framework's default exception handler first,
    # to get the standard error response.
    response = exception_handler(exc, context)

    if isinstance(exc, Throttled): # check that a Throttled exception is raised
        custom_response_data = { # prepare custom response data
            'message': 'request limit exceeded',
            'availableIn': '%d seconds'%exc.wait
        }
        response.data = custom_response_data # set the custom response data on response object

  return response

然后,您需要将这个自定义异常处理程序添加到您的DRF设置中。在

^{pr2}$

我认为如果不更改一些DRF代码,了解throttleType会有点困难,因为DRF会在任何Throttle类限制请求的情况下引发一个Throttled异常。不会将任何信息传递给Throttled异常,throttle_class正在引发该异常。在

我知道这是一个旧的线程,但是除了Rahul的答案之外,还有一种方法可以在消息中包含throttleType:

您首先需要重写Throttled异常类:

  1. 创建一个名为rest_exceptions.py的文件,并创建以下内容:

    import math
    import inspect
    from django.utils.encoding import force_text
    from django.utils.translation import ungettext
    from rest_framework import exceptions, throttling
    
    class CustomThrottled(exceptions.Throttled):
    
        def __init__(self, wait=None, detail=None, throttle_instance=None):
            if throttle_instance is None:
                self.throttle_instance = None
            else:
                self.throttle_instance = throttle_instance
    
            if detail is not None:
                self.detail = force_text(detail)
            else:
                self.detail = force_text(self.default_detail)
    
            if wait is None:
                self.wait = None
            else:
                self.wait = math.ceil(wait)
    

    这里为引发异常的throttle实例添加一个kwarg(如果提供)。您还可以重写详细信息消息的行为,并使用wait值执行您希望的操作。我决定不是连接细节并等待,而是使用原始细节消息。

  2. 接下来,您需要创建一个自定义视图集,该视图集将调节器传递给受限制的异常。创建一个名为rest_viewsets.py的文件并创建以下内容:

    from rest_framework import viewsets
    from .rest_exceptions import CustomThrottled
    
    class ThrottledViewSet(viewsets.ViewSet):
        """
        Adds customizability to the throtted method for better clarity.
        """
    
        throttled_exception_class = CustomThrottled
    
        def throttled(self, request, wait, throttle_instance=None):
            """
            If request is throttled, determine what kind of exception to raise.
            """
            raise self.get_throttled_exception_class()(wait, detail=self.get_throttled_message(request),
                                                       throttle_instance=throttle_instance)
    
        def get_throttled_message(self, request):
            """
            Add a custom throttled exception message to pass to the user.
            Note that this does not account for the wait message, which will be added at the
            end of this message.
            """
            return None
    
        def get_throttled_exception_class(self):
            """
            Return the throttled exception class to use.
            """
            return self.throttled_exception_class
    
        def check_throttles(self, request):
                """
                Check if request should be throttled.
                Raises an appropriate exception if the request is throttled.
                """
                for throttle in self.get_throttles():
                    if not throttle.allow_request(request, self):
                        self.throttled(request, throttle.wait(), throttle_instance=throttle)
    
  3. 既然您有了一个将存储throttle实例的自定义异常,以及一个将实例传递给异常的视图集,那么下一步就是实现一个继承此视图集的视图,并使用您列出的throttle类之一。在您的views.py中,在预期的视图下(因为您没有提供,所以我将其称为MyViewset):

    ^{3美元
  4. 此时,你的应用程序会像往常一样检查节流阀,但也会将传递给throttle实例。我也把油门信息改写成你想要的。我们现在可以使用Rahul提供的解决方案,只需做一些修改。创建自定义异常处理程序:

    from rest_framework.views import exception_handler
    from .rest_exceptions import CustomThrottled
    
    def custom_exception_handler(exc, context):
        # Call REST framework's default exception handler first,
        # to get the standard error response.
        response = exception_handler(exc, context)
    
        if isinstance(exc, CustomThrottled): # check that a CustomThrottled exception is raised
            custom_response_data = { # prepare custom response data
                'message': exc.detail,
                'availableIn': '%d seconds'%exc.wait,
                'throttleType': type(exc.throttle_instance).__name__
            }
            response.data = custom_response_data # set the custom response data on response object
    
      return response
    

    此时您可以轻松地访问throttle类的任何其他属性,但您只需要类名。

  5. 最后,将处理程序添加到DRF设置中:

    REST_FRAMEWORK = {
        'EXCEPTION_HANDLER': 'my_project.my_app.utils.custom_exception_handler'
    }
    

您可以通过重写视图的throttled方法来更改限制响应的消息。例如:

from rest_framework.exceptions import Throttled

class SomeView(APIView):
    def throttled(self, request, wait):
        raise Throttled(detail={
              "message":"request limit exceeded",
              "availableIn":f"{wait} seconds",
              "throttleType":"type"
        })

相关问题 更多 >