我一直在做一项在flask应用程序上应用节流的任务。对于节流,我一直在研究flask-limiter。我的应用程序从flask-restful的资源中扩展了所有端点。
class CompanyApi(Resource):
decorators = [limiter.limit(limit_value="10/minute")]
def get(self):
return "successful"在flask-limiter文档中,它清楚地提到了动态限制可以使用装饰器中的callable加载到基于方法的视图中。
def get_limit():
company = request.args.get('company')
limit = Company.query.get(company)
#returns a limit string stored in db
return limit
@app.route("/check_company", methods=["GET"])
@limiter.limit(limit_value=get_limit)
def check_company():
return "success"而对于可插入的视图,它只提供了硬编码的示例,将装饰器设置为:
decorators = [limiter.limit(limit_value="10/minute")]我尝试在装饰器中设置默认值,当请求正在处理时,我得到了从db检索限制的request params (company)。然后覆盖limiter的limit值:
CompanyApi.decorators = [Limiter.limit(limit_value=get_limit)]它已经改变了,但没有效果。我需要根据请求动态地为每个端点设置限制。
如何实现为基于类的视图设置动态限制?
发布于 2019-05-06 13:39:57
我一直在调查烧瓶限制器的问题,发现有人尝试过custom limiter。我已经找到了一种满足我需求的变通方法。自定义限制器具有以下代码:
class CustomLimiter(Limiter):
def __init__(self):
super().__init__(
key_func=lambda: str(g.user.id) if hasattr(g, 'user') else get_ipaddr(),
auto_check=False,
)
def _evaluate_limits(self, limits):
failed_limit = None
limit_for_header = None
for lim in limits:
limit_scope = request.endpoint
limit_key = lim.key_func()
assert limit_key, 'key expected'
args = [limit_key, limit_scope]
if self._key_prefix:
args = [self._key_prefix] + args
if not limit_for_header or lim.limit < limit_for_header[0]:
limit_for_header = [lim.limit] + args
if not self.limiter.hit(lim.limit, *args):
self.logger.warning(
"ratelimit %s (%s) exceeded at endpoint: %s",
lim.limit, limit_key, limit_scope
)
failed_limit = lim
limit_for_header = [lim.limit] + args
break
g.view_rate_limit = limit_for_header
if failed_limit:
raise RateLimitExceeded(failed_limit.limit)
def limit(self, limit_value, key_func=None):
def _inner(obj):
assert not isinstance(obj, Blueprint)
func = key_func or self._key_func
if callable(limit_value):
limits = [LimitGroup(limit_value, func, None, False, None, None, None)]
else:
limits = list(LimitGroup(limit_value, func, None, False, None, None, None))
@wraps(obj)
def __inner(*a, **k):
self._evaluate_limits(limits)
return obj(*a, **k)
return __inner
return _inner
limiter = CustomLimiter()我在_evaluate_limits中添加了一个检查
def _evaluate_limits(self, limits):
if request:
company = request.args.get('company')
limit = Company.query.get(company)
limits = list(LimitGroup(
limit,
get_company_name, # a callable as a key_func
None,
False,
None,
None,
None
))
#.......在这个修改中,只要Api被实例化,limiter总是设置要处理的默认限制,但只要有请求,它就会通过使用key函数创建key来检查和替换限制。Key确保计数器下一次进行节流。
通过这种方式,我能够实现可插入视图的动态限制行为。
https://stackoverflow.com/questions/55906520
复制相似问题