lesscode-flask 0.2.6__tar.gz → 0.2.7__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {lesscode_flask-0.2.6 → lesscode_flask-0.2.7}/PKG-INFO +2 -12
- {lesscode_flask-0.2.6 → lesscode_flask-0.2.7}/lesscode_flask/__init__.py +1 -1
- {lesscode_flask-0.2.6 → lesscode_flask-0.2.7}/lesscode_flask/app.py +24 -1
- {lesscode_flask-0.2.6 → lesscode_flask-0.2.7}/lesscode_flask/model/base_model.py +1 -1
- {lesscode_flask-0.2.6 → lesscode_flask-0.2.7}/lesscode_flask/setting/__init__.py +31 -1
- lesscode_flask-0.2.7/lesscode_flask/utils/limit/__init__.py +6 -0
- lesscode_flask-0.2.7/lesscode_flask/utils/limit/limit_util.py +50 -0
- lesscode_flask-0.2.7/lesscode_flask/utils/limit/req/rate_limiter_handler.py +28 -0
- lesscode_flask-0.2.7/lesscode_flask/utils/limit/req/redis_rate_limiter.py +62 -0
- lesscode_flask-0.2.7/lesscode_flask/utils/limit/req_count/count_limiter_handler.py +20 -0
- lesscode_flask-0.2.7/lesscode_flask/utils/limit/req_count/redis_count_limiter.py +40 -0
- {lesscode_flask-0.2.6 → lesscode_flask-0.2.7}/lesscode_flask/utils/redis/redis_helper.py +3 -0
- lesscode_flask-0.2.7/lesscode_flask/utils/task/__init__.py +0 -0
- {lesscode_flask-0.2.6 → lesscode_flask-0.2.7}/lesscode_flask.egg-info/PKG-INFO +2 -12
- {lesscode_flask-0.2.6 → lesscode_flask-0.2.7}/lesscode_flask.egg-info/SOURCES.txt +7 -0
- {lesscode_flask-0.2.6 → lesscode_flask-0.2.7}/README.md +0 -0
- {lesscode_flask-0.2.6 → lesscode_flask-0.2.7}/lesscode_flask/db/__init__.py +0 -0
- {lesscode_flask-0.2.6 → lesscode_flask-0.2.7}/lesscode_flask/db/datasource.py +0 -0
- {lesscode_flask-0.2.6 → lesscode_flask-0.2.7}/lesscode_flask/db/executor.py +0 -0
- {lesscode_flask-0.2.6 → lesscode_flask-0.2.7}/lesscode_flask/export_data/__init__.py +0 -0
- {lesscode_flask-0.2.6 → lesscode_flask-0.2.7}/lesscode_flask/export_data/data_download_handler.py +0 -0
- {lesscode_flask-0.2.6 → lesscode_flask-0.2.7}/lesscode_flask/log/access_log_handler.py +0 -0
- {lesscode_flask-0.2.6 → lesscode_flask-0.2.7}/lesscode_flask/model/access_log.py +0 -0
- {lesscode_flask-0.2.6 → lesscode_flask-0.2.7}/lesscode_flask/model/parameterized_query.py +0 -0
- {lesscode_flask-0.2.6 → lesscode_flask-0.2.7}/lesscode_flask/model/resource_param_template.py +0 -0
- {lesscode_flask-0.2.6 → lesscode_flask-0.2.7}/lesscode_flask/model/response_result.py +0 -0
- {lesscode_flask-0.2.6 → lesscode_flask-0.2.7}/lesscode_flask/model/user.py +0 -0
- {lesscode_flask-0.2.6 → lesscode_flask-0.2.7}/lesscode_flask/service/access_log_service.py +0 -0
- {lesscode_flask-0.2.6 → lesscode_flask-0.2.7}/lesscode_flask/service/base_service.py +0 -0
- {lesscode_flask-0.2.6 → lesscode_flask-0.2.7}/lesscode_flask/service/resource_param_template_service.py +0 -0
- {lesscode_flask-0.2.6 → lesscode_flask-0.2.7}/lesscode_flask/setup/__init__.py +0 -0
- {lesscode_flask-0.2.6 → lesscode_flask-0.2.7}/lesscode_flask/signals.py +0 -0
- {lesscode_flask-0.2.6 → lesscode_flask-0.2.7}/lesscode_flask/static/swagger.py +0 -0
- {lesscode_flask-0.2.6/lesscode_flask/utils/decorator → lesscode_flask-0.2.7/lesscode_flask/utils}/__init__.py +0 -0
- {lesscode_flask-0.2.6/lesscode_flask/utils/task → lesscode_flask-0.2.7/lesscode_flask/utils/decorator}/__init__.py +0 -0
- {lesscode_flask-0.2.6 → lesscode_flask-0.2.7}/lesscode_flask/utils/decorator/cache.py +0 -0
- {lesscode_flask-0.2.6 → lesscode_flask-0.2.7}/lesscode_flask/utils/decorator/swagger.py +0 -0
- {lesscode_flask-0.2.6 → lesscode_flask-0.2.7}/lesscode_flask/utils/dify_utils.py +0 -0
- {lesscode_flask-0.2.6 → lesscode_flask-0.2.7}/lesscode_flask/utils/file/file_exporter.py +0 -0
- {lesscode_flask-0.2.6 → lesscode_flask-0.2.7}/lesscode_flask/utils/file/file_utils.py +0 -0
- {lesscode_flask-0.2.6 → lesscode_flask-0.2.7}/lesscode_flask/utils/helpers.py +0 -0
- {lesscode_flask-0.2.6 → lesscode_flask-0.2.7}/lesscode_flask/utils/json/NotSortJSONProvider.py +0 -0
- {lesscode_flask-0.2.6 → lesscode_flask-0.2.7}/lesscode_flask/utils/oss/__init__.py +0 -0
- {lesscode_flask-0.2.6 → lesscode_flask-0.2.7}/lesscode_flask/utils/oss/aliyun_oss.py +0 -0
- {lesscode_flask-0.2.6 → lesscode_flask-0.2.7}/lesscode_flask/utils/oss/ks3_oss.py +0 -0
- {lesscode_flask-0.2.6 → lesscode_flask-0.2.7}/lesscode_flask/utils/oss/minio_oss.py +0 -0
- {lesscode_flask-0.2.6 → lesscode_flask-0.2.7}/lesscode_flask/utils/request/request.py +0 -0
- {lesscode_flask-0.2.6 → lesscode_flask-0.2.7}/lesscode_flask/utils/swagger/swagger_template.py +0 -0
- {lesscode_flask-0.2.6 → lesscode_flask-0.2.7}/lesscode_flask/utils/swagger/swagger_util.py +0 -0
- {lesscode_flask-0.2.6 → lesscode_flask-0.2.7}/lesscode_flask/utils/task/task_helper.py +0 -0
- {lesscode_flask-0.2.6 → lesscode_flask-0.2.7}/lesscode_flask/utils/thread/thread_utils.py +0 -0
- {lesscode_flask-0.2.6 → lesscode_flask-0.2.7}/lesscode_flask/wsgi.py +0 -0
- {lesscode_flask-0.2.6 → lesscode_flask-0.2.7}/lesscode_flask.egg-info/dependency_links.txt +0 -0
- {lesscode_flask-0.2.6 → lesscode_flask-0.2.7}/lesscode_flask.egg-info/requires.txt +0 -0
- {lesscode_flask-0.2.6 → lesscode_flask-0.2.7}/lesscode_flask.egg-info/top_level.txt +0 -0
- {lesscode_flask-0.2.6 → lesscode_flask-0.2.7}/redash/query_runner/__init__.py +0 -0
- {lesscode_flask-0.2.6 → lesscode_flask-0.2.7}/redash/query_runner/clickhouse.py +0 -0
- {lesscode_flask-0.2.6 → lesscode_flask-0.2.7}/redash/query_runner/elasticsearch.py +0 -0
- {lesscode_flask-0.2.6 → lesscode_flask-0.2.7}/redash/query_runner/kingbase.py +0 -0
- {lesscode_flask-0.2.6 → lesscode_flask-0.2.7}/redash/query_runner/mysql.py +0 -0
- {lesscode_flask-0.2.6 → lesscode_flask-0.2.7}/redash/query_runner/pg.py +0 -0
- {lesscode_flask-0.2.6 → lesscode_flask-0.2.7}/redash/settings/__init__.py +0 -0
- {lesscode_flask-0.2.6 → lesscode_flask-0.2.7}/redash/settings/helpers.py +0 -0
- {lesscode_flask-0.2.6 → lesscode_flask-0.2.7}/redash/utils/__init__.py +0 -0
- {lesscode_flask-0.2.6 → lesscode_flask-0.2.7}/redash/utils/requests_session.py +0 -0
- {lesscode_flask-0.2.6 → lesscode_flask-0.2.7}/setup.cfg +0 -0
- {lesscode_flask-0.2.6 → lesscode_flask-0.2.7}/setup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
2
|
Name: lesscode-flask
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.7
|
|
4
4
|
Summary: lesscode-flask 是基于flask的web开发脚手架项目,该项目初衷为简化开发过程,让研发人员更加关注业务。
|
|
5
5
|
Home-page: https://lesscode-flask
|
|
6
6
|
Author: Chao.yy
|
|
@@ -26,16 +26,6 @@ Requires-Dist: gevent==25.5.1
|
|
|
26
26
|
Requires-Dist: openpyxl==3.1.5
|
|
27
27
|
Requires-Dist: iputil==0.3.1
|
|
28
28
|
Requires-Dist: phone==0.4.5
|
|
29
|
-
Dynamic: author
|
|
30
|
-
Dynamic: author-email
|
|
31
|
-
Dynamic: classifier
|
|
32
|
-
Dynamic: description
|
|
33
|
-
Dynamic: description-content-type
|
|
34
|
-
Dynamic: home-page
|
|
35
|
-
Dynamic: platform
|
|
36
|
-
Dynamic: requires-dist
|
|
37
|
-
Dynamic: requires-python
|
|
38
|
-
Dynamic: summary
|
|
39
29
|
|
|
40
30
|
# lesscode-flask
|
|
41
31
|
|
|
@@ -22,10 +22,14 @@ from lesscode_flask.setup import setup_blueprint, setup_logging, setup_query_run
|
|
|
22
22
|
from lesscode_flask.signals import app_runed
|
|
23
23
|
from lesscode_flask.utils.helpers import inject_args, generate_uuid, app_config
|
|
24
24
|
from lesscode_flask.utils.json.NotSortJSONProvider import NotSortJSONProvider
|
|
25
|
+
from lesscode_flask.utils.limit import RedisRateLimiter
|
|
26
|
+
from lesscode_flask.utils.limit.limit_util import get_rate_limit_info, get_count_limit_info
|
|
27
|
+
from lesscode_flask.utils.limit.req.rate_limiter_handler import RateLimitHandler
|
|
28
|
+
from lesscode_flask.utils.limit.req_count.count_limiter_handler import CountLimitHandler
|
|
29
|
+
from lesscode_flask.utils.limit.req_count.redis_count_limiter import RedisCountLimiter
|
|
25
30
|
from lesscode_flask.utils.redis.redis_helper import RedisHelper
|
|
26
31
|
from lesscode_flask.utils.swagger.swagger_util import generate_openapi_spec
|
|
27
32
|
|
|
28
|
-
|
|
29
33
|
# import collections.abc as cabc
|
|
30
34
|
|
|
31
35
|
|
|
@@ -55,9 +59,28 @@ class Lesscoder(Flask):
|
|
|
55
59
|
setting_name = "setting.config.Config"
|
|
56
60
|
self.config.from_object(setting_name)
|
|
57
61
|
self.register_error_handler(Exception, self.handle_exception)
|
|
62
|
+
REDIS_RATE_LIMIT_ENABLE = self.config.get("RATE_LIMIT_ENABLE", False)
|
|
63
|
+
if REDIS_RATE_LIMIT_ENABLE:
|
|
64
|
+
self.rateLimiter = RedisRateLimiter(self.config.get("RATE_LIMIT_KEY", "redis"))
|
|
65
|
+
REDIS_COUNT_LIMIT_ENABLE = self.config.get("COUNT_LIMIT_ENABLE", False)
|
|
66
|
+
if REDIS_COUNT_LIMIT_ENABLE:
|
|
67
|
+
self.countLimiter = RedisCountLimiter(self.config.get("COUNT_LIMIT_KEY", "redis"))
|
|
58
68
|
|
|
59
69
|
def preprocess_request(self) -> ft.ResponseReturnValue | None:
|
|
60
70
|
v = super(Lesscoder, self).preprocess_request()
|
|
71
|
+
|
|
72
|
+
if hasattr(self, 'countLimiter') and self.countLimiter:
|
|
73
|
+
allowed, remaining = self.countLimiter.is_allowed(*get_count_limit_info())
|
|
74
|
+
if not allowed:
|
|
75
|
+
countLimitHandler = self.config.get("COUNT_LIMIT_HANDLER", CountLimitHandler)
|
|
76
|
+
countLimitHandler(request,remaining).response_handler()
|
|
77
|
+
if hasattr(self, 'rateLimiter') and self.rateLimiter:
|
|
78
|
+
# 是否触发限流 延迟时间 超出数量
|
|
79
|
+
allowed,delay, excess = self.rateLimiter.is_limited(*get_rate_limit_info())
|
|
80
|
+
if not allowed :
|
|
81
|
+
rateLimitHandler = self.config.get("RATE_LIMIT_HANDLER", RateLimitHandler)
|
|
82
|
+
rateLimitHandler(request,delay, excess).response_handler()
|
|
83
|
+
|
|
61
84
|
if self.config.get("AUTHORIZATION_ENABLE"): # 启动 AUTHORIZATION_ENABLE 才进行权限验证
|
|
62
85
|
# 获取当前请求的url
|
|
63
86
|
url = request.path
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import os
|
|
2
2
|
import sys
|
|
3
3
|
|
|
4
|
+
from lesscode_flask.utils.limit.req.rate_limiter_handler import RateLimitHandler
|
|
5
|
+
from lesscode_flask.utils.limit.req_count.count_limiter_handler import CountLimitHandler
|
|
6
|
+
|
|
4
7
|
|
|
5
8
|
class BaseConfig:
|
|
6
9
|
# 应用id
|
|
@@ -72,7 +75,10 @@ class BaseConfig:
|
|
|
72
75
|
REDIS_CACHE_KEY = "redis"
|
|
73
76
|
# 权限缓存key
|
|
74
77
|
REDIS_OAUTH_KEY = "oauth2_redis"
|
|
75
|
-
|
|
78
|
+
# 限流频率缓存key
|
|
79
|
+
REDIS_RATE_LIMIT_KEY = "redis"
|
|
80
|
+
# 限流计数缓存key
|
|
81
|
+
REDIS_COUNT_LIMIT_KEY = "redis"
|
|
76
82
|
##**************权限控制相关*****************##
|
|
77
83
|
# 是否启用权限验证
|
|
78
84
|
AUTHORIZATION_ENABLE: bool = False
|
|
@@ -84,6 +90,30 @@ class BaseConfig:
|
|
|
84
90
|
AUTH_DEFAULT_ACCESS = 0
|
|
85
91
|
# 启用生成刷新token
|
|
86
92
|
OAUTH2_REFRESH_TOKEN_GENERATOR = True
|
|
93
|
+
# 是否启用限流频率验证
|
|
94
|
+
RATE_LIMIT_ENABLE: bool = False
|
|
95
|
+
# 触发限流的处理函数
|
|
96
|
+
RATE_LIMIT_HANDLER = RateLimitHandler
|
|
97
|
+
# 限流频率 单位是每秒
|
|
98
|
+
RATE_LIMIT_RATE = 1
|
|
99
|
+
# 限流频率允许的突发值 请求速率超过(rate + brust)的请求会被直接拒绝。
|
|
100
|
+
RATE_LIMIT_BURST = 0
|
|
101
|
+
|
|
102
|
+
# 是否启用限流计数验证
|
|
103
|
+
COUNT_LIMIT_ENABLE: bool = True
|
|
104
|
+
# 触发限流的处理函数
|
|
105
|
+
COUNT_LIMIT_HANDLER = CountLimitHandler
|
|
106
|
+
# 窗口期内最大访问量
|
|
107
|
+
COUNT_LIMIT_COUNT = 5
|
|
108
|
+
# 窗口期时长 单位秒
|
|
109
|
+
COUNT_LIMIT_TIME_WINDOW = 60
|
|
110
|
+
# 白名单
|
|
111
|
+
LIMIT_WHITE_LIST: list = ["/ike2b/user/WXOA/login", "/ike2b/detail/company/node/get_note",
|
|
112
|
+
"/ike2b/user/attention/attention_company_status",
|
|
113
|
+
"/ike2b/pay/wx_pay/sq_coin/get_payment_status",
|
|
114
|
+
"/toolEngine/targetedInvestmentPromotion/get_reach_chain",
|
|
115
|
+
"/ike2b/user/WXOA/bind", "/ike2b/select/park/park_list",
|
|
116
|
+
"/ike2b/pool/company/area_distribution/park_company_count_by_special_tag"]
|
|
87
117
|
#
|
|
88
118
|
# # 外网地址
|
|
89
119
|
# OUTSIDE_SCREEN_IP: str = ""
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import hashlib
|
|
2
|
+
|
|
3
|
+
from flask import request, current_app
|
|
4
|
+
|
|
5
|
+
from lesscode_flask.model.user import flask_login
|
|
6
|
+
from lesscode_flask.utils.helpers import app_config
|
|
7
|
+
def limit_key_encode() -> str:
|
|
8
|
+
limit_key = None
|
|
9
|
+
# 白名单
|
|
10
|
+
limit_white_list = app_config.get("LIMIT_WHITE_LIST", [])
|
|
11
|
+
request_url = request.url_rule.rule
|
|
12
|
+
if request_url in limit_white_list:
|
|
13
|
+
# 白名单访问 直接返回None
|
|
14
|
+
return None
|
|
15
|
+
# 1、获取当前用户
|
|
16
|
+
current_user = flask_login.current_user
|
|
17
|
+
if current_user and not current_user.is_anonymous_user:
|
|
18
|
+
user_id = current_user.id
|
|
19
|
+
# 拼接 key 用户id+url
|
|
20
|
+
limit_key = f"{user_id}:{request_url}"
|
|
21
|
+
# 如果键为空,使用客户端IP
|
|
22
|
+
if not limit_key:
|
|
23
|
+
limit_key = f"{request.remote_addr}{request_url}"
|
|
24
|
+
# 对键进行哈希处理,避免键过长
|
|
25
|
+
limit_key = hashlib.md5(limit_key.encode('utf-8')).hexdigest()
|
|
26
|
+
return hashlib.md5(limit_key.encode('utf-8')).hexdigest()
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def get_rate_limit_info() -> str:
|
|
30
|
+
"""
|
|
31
|
+
获取限流信息,包含限流key 频率 rate , 突发数量 burst:
|
|
32
|
+
:return: 实际使用的限流键
|
|
33
|
+
"""
|
|
34
|
+
rate = app_config.get("RATE_LIMIT_RATE", 1) # 限流频率 单位是每秒
|
|
35
|
+
burst = app_config.get("RATE_LIMIT_BURST", 0) # 限流频率允许的突发值 请求速率超过(rate + brust)的请求会被直接拒绝。
|
|
36
|
+
limit_key = limit_key_encode()
|
|
37
|
+
return limit_key, rate, burst
|
|
38
|
+
|
|
39
|
+
def get_count_limit_info() -> str:
|
|
40
|
+
"""
|
|
41
|
+
获取限流信息,包含限流key 总量 rate , 窗口期 burst:
|
|
42
|
+
:return: 实际使用的限流键
|
|
43
|
+
"""
|
|
44
|
+
# 窗口期内最大访问量
|
|
45
|
+
count = app_config.get("COUNT_LIMIT_COUNT",500)
|
|
46
|
+
# 窗口期时长 单位秒
|
|
47
|
+
time_window = app_config.get("COUNT_LIMIT_TIME_WINDOW",3600)
|
|
48
|
+
limit_key = limit_key_encode()
|
|
49
|
+
return limit_key, count, time_window
|
|
50
|
+
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import time
|
|
2
|
+
import logging
|
|
3
|
+
|
|
4
|
+
from lesscode_flask.model.response_result import ResponseResult
|
|
5
|
+
from lesscode_flask.utils.redis.redis_helper import RedisHelper
|
|
6
|
+
|
|
7
|
+
logger = logging.getLogger(__name__)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class RateLimitHandler:
|
|
11
|
+
"""
|
|
12
|
+
限流后的处理函数实现
|
|
13
|
+
"""
|
|
14
|
+
def __init__(self, req, delay: float, excess: float):
|
|
15
|
+
"""
|
|
16
|
+
初始化
|
|
17
|
+
:param req:
|
|
18
|
+
:param delay: 延迟时间
|
|
19
|
+
:param excess: 超出数量
|
|
20
|
+
"""
|
|
21
|
+
self.req = req
|
|
22
|
+
self.delay = delay
|
|
23
|
+
self.excess = excess
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def response_handler(self):
|
|
27
|
+
message = "请求过于频繁,请稍后再试"
|
|
28
|
+
return ResponseResult.fail(status_code="403", http_code="403", message=message)
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import time
|
|
2
|
+
import logging
|
|
3
|
+
from lesscode_flask.utils.redis.redis_helper import RedisHelper
|
|
4
|
+
|
|
5
|
+
logger = logging.getLogger(__name__)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class RedisRateLimiter:
|
|
9
|
+
"""
|
|
10
|
+
Redis限流实现
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
def __init__(self, redis_key):
|
|
14
|
+
self.redis_key = redis_key
|
|
15
|
+
|
|
16
|
+
def is_limited(self, key: str, rate: float, burst: float) -> tuple:
|
|
17
|
+
"""
|
|
18
|
+
检查是否触发限流
|
|
19
|
+
:param key: 限流键
|
|
20
|
+
:param rate: 每秒请求速率
|
|
21
|
+
:param burst: 突发请求数
|
|
22
|
+
:return: (allowed,delay, excess) 是否触发限流 延迟时间和超出数量
|
|
23
|
+
"""
|
|
24
|
+
if not key: # 没有key表示不验证
|
|
25
|
+
return True, 0,0
|
|
26
|
+
# 构造Redis键
|
|
27
|
+
key = f"limit_req:{key}"
|
|
28
|
+
# 存储键的键
|
|
29
|
+
excess_key = f"{key}excess"
|
|
30
|
+
# 存储最近一次请求时间毫秒的键
|
|
31
|
+
last_key = f"{key}last"
|
|
32
|
+
# 当前时间的毫秒表示形式
|
|
33
|
+
now = time.time() * 1000 # 转换为毫秒
|
|
34
|
+
|
|
35
|
+
try:
|
|
36
|
+
# 获取上次记录的信息
|
|
37
|
+
excess = RedisHelper(self.redis_key).sync_get(excess_key)
|
|
38
|
+
last =RedisHelper(self.redis_key).sync_get(last_key)
|
|
39
|
+
|
|
40
|
+
if excess is not None and last is not None:
|
|
41
|
+
excess = float(excess)
|
|
42
|
+
# 获取最近一次请求的时间毫秒值
|
|
43
|
+
last = float(last)
|
|
44
|
+
# 计算当前与最近一次访问的时间差
|
|
45
|
+
elapsed = now - last
|
|
46
|
+
# 根据时间差计算当前的excess值
|
|
47
|
+
excess = max(excess - (rate * abs(elapsed) / 1000) + 1, 0)
|
|
48
|
+
else:
|
|
49
|
+
excess = 0
|
|
50
|
+
# 返回延迟时间和超出数量
|
|
51
|
+
delay = excess / rate
|
|
52
|
+
# 检查是否超出限制
|
|
53
|
+
if excess > burst+rate:
|
|
54
|
+
return False, delay, excess # 被拒绝
|
|
55
|
+
# 更新Redis中的值
|
|
56
|
+
RedisHelper(self.redis_key).sync_set(excess_key, excess)
|
|
57
|
+
RedisHelper(self.redis_key).sync_set(last_key, now)
|
|
58
|
+
return True,delay, excess
|
|
59
|
+
|
|
60
|
+
except Exception as e:
|
|
61
|
+
logger.error(f"Redis rate limiter error: {e}")
|
|
62
|
+
return True, 0,0
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
|
|
3
|
+
from lesscode_flask.model.response_result import ResponseResult
|
|
4
|
+
|
|
5
|
+
logger = logging.getLogger(__name__)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class CountLimitHandler:
|
|
9
|
+
"""
|
|
10
|
+
限流后的处理函数实现
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
def __init__(self, req, remaining):
|
|
14
|
+
self.req = req
|
|
15
|
+
self.remaining = remaining
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def response_handler(self):
|
|
19
|
+
message = "请求过于频繁,请稍后再试!"
|
|
20
|
+
return ResponseResult.fail(status_code="403", http_code="403", message=message)
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from lesscode_flask.utils.redis.redis_helper import RedisHelper
|
|
3
|
+
|
|
4
|
+
logger = logging.getLogger(__name__)
|
|
5
|
+
|
|
6
|
+
class RedisCountLimiter:
|
|
7
|
+
"""Redis限流计数器实现"""
|
|
8
|
+
|
|
9
|
+
def __init__(self, redis_key):
|
|
10
|
+
self.redis_key = redis_key
|
|
11
|
+
|
|
12
|
+
def is_allowed(self, key, count, time_window, cost=1):
|
|
13
|
+
"""
|
|
14
|
+
检查是否允许请求
|
|
15
|
+
:param key: 限流键
|
|
16
|
+
:param count: 时间窗口内的请求数量限制
|
|
17
|
+
:param time_window: 时间窗口(秒)
|
|
18
|
+
:param cost: 本次请求消耗的令牌数
|
|
19
|
+
:return: (allowed, remaining)
|
|
20
|
+
"""
|
|
21
|
+
if not key: # 没有key表示不验证
|
|
22
|
+
return True, 0
|
|
23
|
+
key = f"limit_count:{key}"
|
|
24
|
+
|
|
25
|
+
try:
|
|
26
|
+
remaining = RedisHelper(self.redis_key).sync_get(key)
|
|
27
|
+
if remaining is None:
|
|
28
|
+
remaining = count-cost
|
|
29
|
+
RedisHelper(self.redis_key).sync_set(key,remaining,time_window)
|
|
30
|
+
else:
|
|
31
|
+
# 键存在,减少令牌数
|
|
32
|
+
remaining = RedisHelper(self.redis_key).sync_incrby(name=key,amount=0- cost)
|
|
33
|
+
if remaining < 0:
|
|
34
|
+
return False, remaining
|
|
35
|
+
else:
|
|
36
|
+
return True, remaining
|
|
37
|
+
except Exception as e:
|
|
38
|
+
# Redis出错时的降级处理
|
|
39
|
+
logger.error(f"Redis count limiter error: {e}")
|
|
40
|
+
return True, remaining
|
|
@@ -30,6 +30,9 @@ class RedisHelper:
|
|
|
30
30
|
def sync_get(self, name):
|
|
31
31
|
return self.get_connection().get(name)
|
|
32
32
|
|
|
33
|
+
def sync_incrby(self, name,amount):
|
|
34
|
+
return self.get_connection().incrby(name,amount)
|
|
35
|
+
|
|
33
36
|
def sync_keys(self, pattern):
|
|
34
37
|
return self.get_connection().keys(pattern=pattern)
|
|
35
38
|
|
|
File without changes
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
2
|
Name: lesscode-flask
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.7
|
|
4
4
|
Summary: lesscode-flask 是基于flask的web开发脚手架项目,该项目初衷为简化开发过程,让研发人员更加关注业务。
|
|
5
5
|
Home-page: https://lesscode-flask
|
|
6
6
|
Author: Chao.yy
|
|
@@ -26,16 +26,6 @@ Requires-Dist: gevent==25.5.1
|
|
|
26
26
|
Requires-Dist: openpyxl==3.1.5
|
|
27
27
|
Requires-Dist: iputil==0.3.1
|
|
28
28
|
Requires-Dist: phone==0.4.5
|
|
29
|
-
Dynamic: author
|
|
30
|
-
Dynamic: author-email
|
|
31
|
-
Dynamic: classifier
|
|
32
|
-
Dynamic: description
|
|
33
|
-
Dynamic: description-content-type
|
|
34
|
-
Dynamic: home-page
|
|
35
|
-
Dynamic: platform
|
|
36
|
-
Dynamic: requires-dist
|
|
37
|
-
Dynamic: requires-python
|
|
38
|
-
Dynamic: summary
|
|
39
29
|
|
|
40
30
|
# lesscode-flask
|
|
41
31
|
|
|
@@ -27,6 +27,7 @@ lesscode_flask/service/resource_param_template_service.py
|
|
|
27
27
|
lesscode_flask/setting/__init__.py
|
|
28
28
|
lesscode_flask/setup/__init__.py
|
|
29
29
|
lesscode_flask/static/swagger.py
|
|
30
|
+
lesscode_flask/utils/__init__.py
|
|
30
31
|
lesscode_flask/utils/dify_utils.py
|
|
31
32
|
lesscode_flask/utils/helpers.py
|
|
32
33
|
lesscode_flask/utils/decorator/__init__.py
|
|
@@ -35,6 +36,12 @@ lesscode_flask/utils/decorator/swagger.py
|
|
|
35
36
|
lesscode_flask/utils/file/file_exporter.py
|
|
36
37
|
lesscode_flask/utils/file/file_utils.py
|
|
37
38
|
lesscode_flask/utils/json/NotSortJSONProvider.py
|
|
39
|
+
lesscode_flask/utils/limit/__init__.py
|
|
40
|
+
lesscode_flask/utils/limit/limit_util.py
|
|
41
|
+
lesscode_flask/utils/limit/req/rate_limiter_handler.py
|
|
42
|
+
lesscode_flask/utils/limit/req/redis_rate_limiter.py
|
|
43
|
+
lesscode_flask/utils/limit/req_count/count_limiter_handler.py
|
|
44
|
+
lesscode_flask/utils/limit/req_count/redis_count_limiter.py
|
|
38
45
|
lesscode_flask/utils/oss/__init__.py
|
|
39
46
|
lesscode_flask/utils/oss/aliyun_oss.py
|
|
40
47
|
lesscode_flask/utils/oss/ks3_oss.py
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{lesscode_flask-0.2.6 → lesscode_flask-0.2.7}/lesscode_flask/export_data/data_download_handler.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{lesscode_flask-0.2.6 → lesscode_flask-0.2.7}/lesscode_flask/model/resource_param_template.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{lesscode_flask-0.2.6 → lesscode_flask-0.2.7}/lesscode_flask/utils/json/NotSortJSONProvider.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{lesscode_flask-0.2.6 → lesscode_flask-0.2.7}/lesscode_flask/utils/swagger/swagger_template.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|