Как установить динамический лимит для подключаемых видов с помощью колбы? - PullRequest
1 голос
/ 29 апреля 2019

Я работал над задачей применить регулирование дросселирования в приложении для колб. Для регулирования я искал ограничитель колбы . Мое приложение имеет все конечные точки, расширенные из ресурса flask-restful.

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

    def get(self):
        return "successful"

В документации на колбу-ограничитель четко указано, что динамические пределы можно загружать с помощью функции 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")]

Я пытался установить значение по умолчанию в декораторах, и когда запрос обрабатывается, я получаю параметры запроса (компания), для которых извлекается лимит из дб. Затем перезаписывается предельное значение ограничителя:

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

Это было изменено, но не эффективно. Мне нужно установить лимит для каждой конечной точки динамически на основе запроса.

Как мне установить динамические ограничения для представлений на основе классов?

1 Ответ

0 голосов
/ 06 мая 2019

Я изучал проблемы с колб-ограничителем и обнаружил, что кто-то пробовал настраиваемый ограничитель .Я нашел обходной путь для удовлетворения моих требований.Пользовательский ограничитель имеет следующий код:

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,но всякий раз, когда есть запрос, он проверяет и заменяет ограничения, создавая ключ с помощью функции ключа.Ключ обеспечивает счетчик на следующий раз для регулирования.

Таким образом, я смог добиться динамического ограничения поведения для подключаемых представлений.

...