django rest framework之节流的源码流程剖析

本文详细介绍了在RESTful API设计中,如何通过自定义视图类实现用户注册和信息检索的功能,并深入探讨了节流类的实现,用于限制API的调用频率,防止恶意攻击和资源滥用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

视图类:

 1 class UserViewset(BaseView):
 2     '''
 3         create:
 4         创建用户
 5         retrieve:
 6 
 7     '''
 8     queryset = User.objects.all()
 9     throttle_classes = [UserRateThrottle] #添加节流类
10     authentication_classes = (JSONWebTokenAuthentication, authentication.SessionAuthentication)
11     def get_serializer_class(self):
12         self.dispatch
13         if self.action == "retrieve":
14             return UserDetailSerializer
15         elif self.action == "create":
16             return UserRegSerializer
17 
18         return UserDetailSerializer
19 
20     def get_permissions(self):
21         if self.action == "retrieve":
22             return [permissions.IsAuthenticated()]
23         elif self.action == "create":
24             return []
25 
26         return []
27 
28     def create(self, request, *args, **kwargs):
29         serializer = self.get_serializer(data=request.data)
30         serializer.is_valid(raise_exception=True)
31         user = self.perform_create(serializer)
32         re_dict = serializer.data
33         payload = jwt_payload_handler(user)
34         re_dict["token"] = jwt_encode_handler(payload)
35         re_dict["name"] = user.name if user.name else user.username
36 
37         headers = self.get_success_headers(serializer.data)
38         return Response(re_dict, status=status.HTTP_201_CREATED, headers=headers)
39 
40     def get_object(self):
41         return self.request.user
42 
43     def perform_create(self, serializer):
44         return serializer.save()

通权限类一样在中调用:

1     def check_throttles(self, request):
2         """
3         Check if request should be throttled.
4         Raises an appropriate exception if the request is throttled.
5         """
6         for throttle in self.get_throttles():
7             if not throttle.allow_request(request, self): #验证是不是要被节流
8                 self.throttled(request, throttle.wait())  #验证不通过就返回响应

内置节流类:

  1 class BaseThrottle(object):
  2     """
  3     Rate throttling of requests.
  4     """
  5 
  6     def allow_request(self, request, view):
  7         """
  8         Return `True` if the request should be allowed, `False` otherwise.
  9         """
 10         raise NotImplementedError('.allow_request() must be overridden')
 11 
 12     def get_ident(self, request): 获取访问IP
 13         """
 14         Identify the machine making the request by parsing HTTP_X_FORWARDED_FOR
 15         if present and number of proxies is > 0. If not use all of
 16         HTTP_X_FORWARDED_FOR if it is available, if not use REMOTE_ADDR.
 17         """
 18         xff = request.META.get('HTTP_X_FORWARDED_FOR')
 19         remote_addr = request.META.get('REMOTE_ADDR')
 20         num_proxies = api_settings.NUM_PROXIES
 21 
 22         if num_proxies is not None:
 23             if num_proxies == 0 or xff is None:
 24                 return remote_addr
 25             addrs = xff.split(',')
 26             client_addr = addrs[-min(num_proxies, len(addrs))]
 27             return client_addr.strip()
 28 
 29         return ''.join(xff.split()) if xff else remote_addr
 30 
 31     def wait(self):
 32         """
 33         Optionally, return a recommended number of seconds to wait before
 34         the next request.
 35         """
 36         return None
 37 
 38 
 39 class SimpleRateThrottle(BaseThrottle):
 40     """
 41     A simple cache implementation, that only requires `.get_cache_key()`
 42     to be overridden.
 43 
 44     The rate (requests / seconds) is set by a `rate` attribute on the View
 45     class.  The attribute is a string of the form 'number_of_requests/period'.
 46 
 47     Period should be one of: ('s', 'sec', 'm', 'min', 'h', 'hour', 'd', 'day')
 48 
 49     Previous request information used for throttling is stored in the cache.
 50     """
 51     cache = default_cache
 52     timer = time.time
 53     cache_format = 'throttle_%(scope)s_%(ident)s'
 54     scope = None
 55     THROTTLE_RATES = api_settings.DEFAULT_THROTTLE_RATES  #获取配置
 56 
 57     def __init__(self):
 58         if not getattr(self, 'rate', None):
 59             self.rate = self.get_rate()
 60         self.num_requests, self.duration = self.parse_rate(self.rate)
 61 
 62     def get_cache_key(self, request, view):
 63         """
 64         Should return a unique cache-key which can be used for throttling.
 65         Must be overridden.
 66 
 67         May return `None` if the request should not be throttled.
 68         """
 69         raise NotImplementedError('.get_cache_key() must be overridden')
 70 
 71     def get_rate(self): #获取配置的参数
 72         """
 73         Determine the string representation of the allowed request rate.
 74         """
 75         if not getattr(self, 'scope', None):
 76             msg = ("You must set either `.scope` or `.rate` for '%s' throttle" %
 77                    self.__class__.__name__)
 78             raise ImproperlyConfigured(msg)
 79 
 80         try:
 81             return self.THROTTLE_RATES[self.scope]
 82         except KeyError:
 83             msg = "No default throttle rate set for '%s' scope" % self.scope
 84             raise ImproperlyConfigured(msg)
 85 
 86     def parse_rate(self, rate): #获取定义里的节流策略如3/m,每分钟访问3次
 87         """
 88         Given the request rate string, return a two tuple of:
 89         <allowed number of requests>, <period of time in seconds>
 90         """
 91         if rate is None:
 92             return (None, None)
 93         num, period = rate.split('/')
 94         num_requests = int(num)
 95         duration = {'s': 1, 'm': 60, 'h': 3600, 'd': 86400}[period[0]]
 96         return (num_requests, duration)
 97 
 98     def allow_request(self, request, view):
 99         """
100         Implement the check to see if the request should be throttled.
101 
102         On success calls `throttle_success`.
103         On failure calls `throttle_failure`.
104         """
105         if self.rate is None:
106             return True
107 
108         self.key = self.get_cache_key(request, view) #获取存储的key
109         if self.key is None:
110             return True
111 
112         self.history = self.cache.get(self.key, []) #获取访问历史
113         self.now = self.timer()
114 
115         # Drop any requests from the history which have now passed the
116         # throttle duration
117         while self.history and self.history[-1] <= self.now - self.duration:
118             self.history.pop()
119         if len(self.history) >= self.num_requests: #判断
120             return self.throttle_failure()
121         return self.throttle_success()
122 
123     def throttle_success(self):
124         """
125         Inserts the current request's timestamp along with the key
126         into the cache.
127         """
128         self.history.insert(0, self.now)
129         self.cache.set(self.key, self.history, self.duration)
130         return True
131 
132     def throttle_failure(self):
133         """
134         Called when a request to the API has failed due to throttling.
135         """
136         return False
137 
138     def wait(self):  #返回响应
139         """
140         Returns the recommended next request time in seconds.
141         """
142         if self.history:
143             remaining_duration = self.duration - (self.now - self.history[-1])
144         else:
145             remaining_duration = self.duration
146 
147         available_requests = self.num_requests - len(self.history) + 1
148         if available_requests <= 0:
149             return None
150 
151         return remaining_duration / float(available_requests)
152 class UserRateThrottle(SimpleRateThrottle): 153 """ 154 Limits the rate of API calls that may be made by a given user. 155 156 The user id will be used as a unique cache key if the user is 157 authenticated. For anonymous requests, the IP address of the request will 158 be used. 159 """ 160 scope = 'user' 161 162 def get_cache_key(self, request, view): 163 if request.user.is_authenticated: #如果用户是登录后的就返回用户的id 164 ident = request.user.pk 165 else: 166 ident = self.get_ident(request) #返回请求的ip 167 168 return self.cache_format % { 169 'scope': self.scope, 170 'ident': ident 171 }

 

转载于:https://www.cnblogs.com/arrow-kejin/p/9988271.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值