2015-10-04 184 views
4

我正在使用DRF来休息apis,所以现在我正在对我的apis应用节流。对于我创建以下油门范围django rest框架中的自定义节流响应

  1. userRateThrottle

  2. anonRateThrottle

  3. burstRateThrottle

  4. perViewsThrottles(可观看而异)

目前我得到是低响应:

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

我想回应是这样的:

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

中没有任何DRF文档进行定制。我如何根据需求定制我的回复?

回答

10

要做到这一点,您可以使用执行custom exception handler function,如果发生Throttled异常,将返回自定义响应。

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设置。

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

我认为这将是稍微很难知道throttleType不改变一些DRF代码DRF在任何节气门类节流的请求的情况下,提出了一个Throttled例外。没有任何信息传递给Throttled例外,即哪个throttle_class正在引发该异常。

0

我知道这是一个古老的线程,但增加了拉胡尔的回答,这里有一个办法,包括在消息中throttleType:

首先你需要重写节流异常类:

  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) 
    

    在这里,您添加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. 现在你已经将存储油门例如一个自定义异常,这将实例传递到异常的视图集,下一步就是实现一个继承此视图集的视图,并且还使用您列出的某个油门类。在你views.py,预期视图下(因为你没有提供,我要叫它MyViewset):

    from .rest_viewsets import ThrottledViewSet 
    from rest_framework import throttling 
    
    class MyViewset(ThrottledViewSet): 
        throttle_classes = (throttling.userRateThrottle,) # Add more here as you wish 
        throttled_exception_class = CustomThrottled # This is the default already, but let's be specific anyway 
    
        def get_throttled_message(self, request): 
         """Add a custom message to the throttled error.""" 
         return "request limit exceeded" 
    
  4. 在这一点上,你的应用程序将检查像往常一样油门,但会通过油门实例。我也将节流消息覆盖到你想要的东西上。现在我们可以利用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 
    

    你可以很容易地在这点上访问油门类的任何其他属性,但你只想要的类名。

  5. 最后但并非最不重要的,你的处理程序添加到DRF设置:

    REST_FRAMEWORK = { 
        'EXCEPTION_HANDLER': 'my_project.my_app.utils.custom_exception_handler' 
    } 
    
相关问题