2015-10-04 6 views
4

Я использую DRF для отдыха apis, поэтому теперь я применяю дросселирование к своей apis. Для этого я создал следующие дроссельных прицеловПользовательский дросселирующий отклик в каркасе отдыха django

  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 кода, как ФПИ поднимает 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. Теперь, когда у вас есть пользовательское исключение, которое будет хранить экземпляр дросселем, и Viewset, которое передаст экземпляр исключения, ваш следующий шаг заключается в реализации представление, которое наследует этот вид, а также использует один из перечисленных вами дроссельных классов. В вашем 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. На данный момент, ваше приложение будет проверять дросселей, как обычно, но будет также проходят вместе с экземпляром дроссельной заслонки. Я также переопределил сообщение дроссельной заслонки тем, что вы хотели. Теперь мы можем использовать решение, которое предоставил Рахул, с несколькими изменениями. Создание обработчика исключений:

    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' 
    }