首页 科技正文

allbet登陆官网:Flask-Limit使用详细说明

admin 科技 2020-07-11 42 0

Flask-Limit详细说明

在flask项目中我们需要对所有或者一部门接口举行限制,又不想造轮子,那怎么办呢?

以是这就是flask-limit泛起的缘故原由,不外对于相对庞大的需求,照样自己造轮子吧!

安装与简朴使用

安装:pip install Flask-Limiter

快速最先:

from flask import Flask
from flask_limiter import Limiter
from flask_limiter.util import get_remote_address

app = Flask(__name__)
limiter = Limiter(
    app,
    key_func=get_remote_address,
    default_limits=["200 per day", "50 per hour"]
)
@app.route("/slow")
@limiter.limit("1 per day")
def slow():
    return ":("

@app.route("/medium")
@limiter.limit("1/second", override_defaults=False)
def medium():
    return ":|"

@app.route("/fast")
def fast():
    return ":)"

@app.route("/ping")
@limiter.exempt
def ping():
    return "PONG"

上诉频率限制说明:

  • 默认通过请求的remote_address举行限制。
  • 默认限制为200次/天,50次/小时;适用于所有门路
  • slow路由的限制将绕过默认的速率限制,为1次/天
  • medium路由继续默认限制,并增加了1次/秒的限制
  • ping路由不受任何默认速率限制的约束

注重: 静态路由不受速率限制

每次请求超出速率限制时,将不会挪用view函数,而是会引发429http错误。

速率限制规则:

[count] [per|/] [n (optional)] [second|minute|hour|day|month|year]

可以使用自己选择的分开符将多个速率限制组合起来。

示例:

  • 10 per hour
  • 10/hour
  • 10/hour;100/day;2000 per year
  • 100/day, 500/7days

使用的详细说明

看完上面的部门实在已经知足大部门需求了,然则真实的情形下,可能还存在其他的定制服务,以下就是详细说明。

初始化

初始化有两种方式:

  1. 使用组织函数

    from flask_limiter import Limiter
    from flask_limiter.util import get_remote_address
    ....
    
    limiter = Limiter(app, key_func=get_remote_address)
    
  2. 使用延迟应用初始化 init_app

    limiter = Limiter(key_func=get_remote_address)
    limiter.init_app(app)
    

现实开发中更有可能使用的是延迟初始化。

装饰器

我们所使用的是已建立的Limiter示例的limit方式,可凭据喜欢和使用场景,有以下几种使用方式:

单装饰

@app.route("....")
@limiter.limit("100/day;10/hour;1/minute")
def my_route()
  ...

多装饰

@app.route("....")
@limiter.limit("100/day")
@limiter.limit("10/hour")
@limiter.limit("1/minute")
def my_route():
  ...

新增自定义的功效

下方会有详细先容此装饰器内的参数的说明

def my_key_func():
  ...

@app.route("...")
@limiter.limit("100/day", my_key_func)
def my_route():
  ...

限制域

即指定凭据什么举行限制,对应的参数为key_funcflask_limiter.util提供了两种方式:

  • flask_limiter.util.get_ipaddr(): 使用X-Forwarded-For标头中的最后一个IP地址,否则回退到请求的remote_address(不建议使用)
  • flask_limiter.util.get_remote_address(): 使用请求的remote_address

在真实开发中,大部门项目都配备了Nginx,以是若是直接使用get_remote_address的话获取到的是Nginx服务器的地址,异常危险!!!

以是项目中很有可能都是自定义key_func!

搭载Nginx服务器的key_func示例:

def limit_key_func():
    return str(flask_request.headers.get("X-Forwarded-For", '127.0.0.1'))

不外以上设置的依据照样凭据Nginx的设置决议的,有兴趣的同砚还可以领会一下X-Forwarded-ForX-Real-IP的区别。

X-Forwarded-For 一样平常是每一个非透明署理转发请求时会将上游服务器的ip地址追加到X-Forwarded-For的后面,使用英文逗号支解 ;

X-Real-IP一样平常是最后一级署理将上游ip地址添加到该头中 ;

X-Forwarded-For是多个ip地址,而X-Real-IP是一个;

若是只有一层署理,这两个头的值就是一样的。

以是上方自定义的方式仅作参考。

动态加载限制字符串

常见的限制规则已在上文先容过,这里先容的在某些情形下,需要从代码外部的源(数据库,远程api等)中检索速率限制。

def rate_limit_from_config():
    return current_app.config.get("CUSTOM_LIMIT", "10/s")

@app.route("...")
@limiter.limit(rate_limit_from_config)
def my_route():
    ...

所装饰的路由上的每个请求都市挪用提供的可挪用工具。对于昂贵的检索,请思量缓存响应。

宽免条件

小我私家以为这可以从两个方面来谈,一是针对key,一是针对计次,以下我们划分举行先容。

  • 白名单:

    • 方式一:参数为exempt_when,设置这个参数将不被频率限制。

      @app.route("/expensive")
      @limiter.limit("100/day", exempt_when=lambda: current_user.is_admin)
      def expensive_route():
        ...
      
    • 方式二:请求过滤器Limiter.request_filter()方式(没研究)

      @limiter.request_filter
      def header_whitelist():
          return request.headers.get("X-Internal", "") == "true"
      
      @limiter.request_filter
      def ip_whitelist():
          return request.remote_addr == "127.0.0.1"
      
  • 不计次情形:参数为deduct_when,判断某些情形不计入使用频率的次数。

    def func_deduct(response):
        """
        频率限制之凭据response决议是否计次
        :param response: flask.wrappers.Response工具
        :return: 计次返回True
        """
        # 正常响应状态码:200
        res = response.response if response._status_code == 200 else None
        if res:
            res = json.loads(res[0])
            # 有响应数据,记一次
            return res.get("code") == 200
    
        return False
    
    
    @api.route('/captcha')
    @limit.limit("5/day;3/hour", deduct_when=func_deduct)
    def expensive_route():
      ...
    
  • 路由宽免:此情形特殊,属于某个路由不介入频率限制,使用方式为

    limiter.exempt()
    

共享限制

适用于速率限制应由多条路由共享的情形。

命名共享限制

mysql_limit = limiter.shared_limit("100/hour", scope="mysql")

@app.route("..")
@mysql_limit
def r1():
   ...

@app.route("..")
@mysql_limit
def r2():
   ...

动态共享限制:将可挪用工具作为局限通报时,该函数的返回值将用作局限。

def host_scope(endpoint_name):
    return request.host
host_limit = limiter.shared_limit("100/hour", scope=host_scope)

@app.route("..")
@host_limit
def r1():
   ...

@app.route("..")
@host_limit
def r2():
   ...

共享限制使用上与单个限制一致

设置

参数 说明
RATELIMIT_DEFAULT 默认计谋, 逗号分开('1/minute,100/hour')
RATELIMIT_DEFAULTS_PER_METHOD 是按方式/门路应用默认限制,照样按方式将所有方式组合应用默认限制。
RATELIMIT_DEFAULTS_EXEMPT_WHEN 默认宽免条件
RATELIMIT_APPLICATION 应用计谋,用于将限制应用于整个应用程序(即,由所有路由共享)。
RATELIMIT_STORAGE_URL 存储位置:
  • 内存:memcached://host:port
  • Redis: redis://host:port |
    | RATELIMIT_STORAGE_OPTIONS | 一个字典,用于设置要在初始化时通报给存储实现的其他选项。 |
    | RATELIMIT_STRATEGY | 使用的限速计谋。详见限速计谋 |
    | RATELIMIT_HEADERS_ENABLED | 是否返回速率限制的相关信息到reponse header中。默以为False,与上一条一样可以忽视。 |
    | RATELIMIT_ENABLED | 速率限制的总体终止开关。默以为True |
    | RATELIMIT_HEADER_LIMIT | 当前速率限制的题目。默以为X-RateLimit-Limit |
    | RATELIMIT_HEADER_RESET | 当前速率限制的重置时间的题目。默以为X-RateLimit-Reset |
    | RATELIMIT_HEADER_REMAINING | 当前速率限制中剩余的请求数的标头。默以为X-RateLimit-Remaining |
    | RATELIMIT_HEADER_RETRY_AFTER | 客户端应何时重试请求的标头。默以为Retry-After |
    | RATELIMIT_SWALLOW_ERRORS | 默认False即可 |
    | RATELIMIT_IN_MEMORY_FALLBACK_ENABLED | 若是启用,则当设置的存储关闭时,内存中的速率限制器将用作备用。与RATELIMIT_IN_MEMORY_FALLBACK原始速率限制连系使用时,将不会继续该限制 |
    | RATELIMIT_IN_MEMORY_FALLBACK | 后端存储异常使用的计谋设置 |
    | RATELIMIT_KEY_PREFIX | 存储key的前缀设置 |

速度限制计谋

Flask-Limiter内置了三种差别的速率限制计谋。

划分为: Fixed Window、Fixed Window with Elastic Expiry、Moving Window

暂未研究,不做先容。

错误响应

超出限制的请求返回的都是429状态码,示例如下:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<title>429 Too Many Requests</title>
<h1>Too Many Requests</h1>
<p>1 per 1 day</p>

若是要设置响应,可对路由状态码判断后响应,示例如下:

@app.errorhandler(429)
def ratelimit_handler(e):
    return make_response(
            jsonify(error="ratelimit exceeded %s" % e.description)
            , 429
    )

固然,还可以自定义错误信息:

app = Flask(__name__)
limiter = Limiter(app, key_func=get_remote_address)

def error_handler():
    return app.config.get("DEFAULT_ERROR_MESSAGE")

@app.route("/")
@limiter.limit("1/second", error_message='chill!')
def index():
    ....

@app.route("/ping")
@limiter.limit("10/second", error_message=error_handler)
def ping():
    ....

CBV与Blueprint使用

FBV可以使用装饰器的方式举行限制,然则对于CBV就有些不适用了,以下就是CBV的使用方式。

app = Flask(__name__)
limiter = Limiter(app, key_func=get_remote_address)

class MyView(flask.views.MethodView):
    decorators = [limiter.limit("10/second")]
    def get(self):
        return "get"

    def put(self):
        return "put"

CBV的方式照样有些麻烦了,若是能对蓝图下所有的路由都举行限制就更好了,也可以对某个蓝图举行宽免。

app = Flask(__name__)
login = Blueprint("login", __name__, url_prefix = "/login")
regular = Blueprint("regular", __name__, url_prefix = "/regular")
doc = Blueprint("doc", __name__, url_prefix = "/doc")

@doc.route("/")
def doc_index():
    return "doc"

@regular.route("/")
def regular_index():
    return "regular"

@login.route("/")
def login_index():
    return "login"


limiter = Limiter(app, default_limits=["1/second"], key_func=get_remote_address)
limiter.limit("60/hour")(login)
limiter.exempt(doc)

app.register_blueprint(doc)
app.register_blueprint(login)
app.register_blueprint(regular)

关于署理

虽然上文说过Nginx署理的情形需要更庞大的操作,不外在查看官方文档的时刻,还发现了一个简朴的方式,说明如下:

若是您的应用程序位于署理之后,而且您使用的是werkzeug> 0.9+,则可以使用werkzeug.contrib.fixers.ProxyFix 修复程序可靠地获取用户的远程地址,同时珍爱您的应用程序免于通过标头举行ip诱骗。

from flask import Flask
from flask_limiter import Limiter
from flask_limiter.util import get_remote_address
from werkzeug.contrib.fixers import ProxyFix

app = Flask(__name__)
# for example if the request goes through one proxy
# before hitting your application server
app.wsgi_app = ProxyFix(app.wsgi_app, num_proxies=1)
limiter = Limiter(app, key_func=get_remote_address)

API

flask_limit.Limiter类初始化属性,Limiter(app=None, key_func=None, global_limits=[], default_limits=[], default_limits_per_method=False, default_limits_exempt_when=None, default_limits_deduct_when=None, application_limits=[], headers_enabled=False, strategy=None, storage_uri=None, storage_options={}, auto_check=True, swallow_errors=False, in_memory_fallback=[], in_memory_fallback_enabled=False, retry_after=None, key_prefix='', enabled=True)

参数 说明
app 即flask的项目
key_func 限制域
default_limits 默认限制计谋
default_limits_per_method 默认限制是按方式/门路应用照样按每种方式所有方式的组合应用。
default_limits_exempt_when 默认宽免条件
default_limits_deduct_when 吸收response工具并返回True / False以决议是否应从默认速率限制中扣除的函数
application_limits 所有路由的共享限制
headers_enabled 是否写入响应头
storage_uri 存储位置
storage_options 意义不明的分外设置
auto_check 是否自动检查应用程序的before_request链中的速率限制。默认True
swallow_errors 到达速率限制时会纪录异常。默认False
in_memory_fallback 字符串或可挪用项的可变列表,返回示意存储空间不足时要应用的回退限制的字符串
in_memory_fallback_enabled 仅在主存储关闭并继续原始限制时才退回到内存存储中。
key_prefix 前缀
strategy 计谋

方式:

check()

exempt()

ini_app()

request_filter()

reset()

limit(limit_value, key_func=None, per_method=False, methods=None, error_message=None, exempt_when=None, override_defaults=True, deduct_when=None)

shared_limit(limit_value, scope, key_func=None, error_message=None, exempt_when=None, override_defaults=True, deduct_when=None)

,

欧博开户网址

欢迎进入欧博开户网址(Allbet Gaming):www.aLLbetgame.us,欧博网址开放会员注册、代理开户、电脑客户端下载、苹果安卓下载等业务。

版权声明

本文仅代表作者观点,
不代表本站申博官网的立场。
本文系作者授权发表,未经许可,不得转载。

评论