2015-10-04 178 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' 
    } 
    
相關問題