[英]How to set dynamic limit for pluggable views using flask?
I've been working on a task to apply throttling on a flask app. 我一直在研究在烧瓶应用程序上应用节流的任务。 For throttling, I've been looking into flask-limiter .
为了节流,我一直在研究flask-limiter 。 My app has all endpoints extended from flask-restful's Resource.
我的应用程序具有从flask-restful的Resource扩展的所有端点。
class CompanyApi(Resource):
decorators = [limiter.limit(limit_value="10/minute")]
def get(self):
return "successful"
From flask-limiter doc, its clearly mentioned that dynamic limits can be loaded using callable in decorator for method based views. 从flask-limiter文档中,它明确提到可以在基于方法的视图的decorator中使用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"
While for pluggable views, its only provided the hardcoded example by setting the decorator as: 对于可插入视图,它仅通过将装饰器设置为以下方式提供了硬编码示例:
decorators = [limiter.limit(limit_value="10/minute")]
I've tried by setting default value in decorators and when request is processing, I get request params (company) on which limit is retrieved from db. 我尝试通过在装饰器中设置默认值来进行尝试,并且在处理请求时,得到了从数据库检索限制的请求参数(公司)。 Then overwriting limiter's limit value:
然后覆盖限制器的极限值:
CompanyApi.decorators = [Limiter.limit(limit_value=get_limit)]
It's been changed but not effective. 它已更改,但无效。 I need to set limit for each endpoint dynamically on the basis of request.
我需要根据请求动态设置每个端点的限制。
How can I achieve to set dynamic limits for class based views? 如何实现为基于类的视图设置动态限制?
I've been looking into flask-limiter issues and found someone has tried custom limiter . 我一直在研究烧瓶限制器问题,发现有人尝试了自定义限制器 。 I had found a workaround to meet my requirements.
我找到了一种解决方法来满足我的要求。 Custom limiter has following code:
自定义限制器具有以下代码:
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()
I added a check into _evaluate_limits
: 我在
_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
))
#.......
In this modification, limiter always sets defaults limits to process whenever the Api is instantiated, but whenever there is a request, it will check and replace the limits by creating a key using key function. 在此修改中,限制器始终设置默认限制以在实例化Api时进行处理,但是每当有请求时,它将通过使用键功能创建键来检查并替换限制。 Key insures the counter for next time for throttling.
密钥可确保计数器下次进行节流。
In this way I was able to achieve dynamic limit behaviour for pluggable views. 这样,我就可以实现可插入视图的动态限制行为。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.