【问题标题】:How to set dynamic limit for pluggable views using flask?如何使用烧瓶设置可插入视图的动态限制?
【发布时间】:2019-09-18 06:21:00
【问题描述】:

我一直在处理一项在烧瓶应用程序上应用节流的任务。对于节流,我一直在研究flask-limiter。我的应用程序的所有端点都是从 flask-restful 的资源扩展而来的。

class CompanyApi(Resource):
    decorators = [limiter.limit(limit_value="10/minute")]

    def get(self):
        return "successful"

从flask-limiter doc,它清楚地提到动态限制可以使用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"

虽然对于可插入视图,它仅通过将装饰器设置为提供硬编码示例:

decorators = [limiter.limit(limit_value="10/minute")]

我已经尝试通过在装饰器中设置默认值,并且在处理请求时,我得到了从中检索限制的请求参数(公司) D b。然后覆盖限制器的限制值:

CompanyApi.decorators = [Limiter.limit(limit_value=get_limit)]

已更改但无效。我需要根据请求动态设置每个端点的限制。

如何为基于类的视图设置动态限制?

【问题讨论】:

    标签: python python-3.x api flask throttling


    【解决方案1】:

    我一直在研究烧瓶限制器问题,发现有人尝试过 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
                ))
            #.......
    

    在此修改中,limiter 总是在实例化 Api 时设置默认限制来处理,但每当有请求时,它会通过使用 key 函数创建 key 来检查和替换限制。键确保计数器下次节流。

    通过这种方式,我能够实现可插入视图的动态限制行为。

    【讨论】:

      猜你喜欢
      • 2017-09-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-04-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多