DRF的SimpleRateThrottle必须重写get_cache_key才能生效,因其默认仅对匿名用户限流;需返回非None字符串作为缓存键,且scope须与DEFAULT_THROTTLE_RATES中的键名一致,配合Redis缓存方可稳定生效。
DRF的
必须重写
才能生效
很多人配了
却没效果,根本原因是DRF默认只对匿名用户限流。只要用户已登录,
就完全不触发,而
又默认按
限流——但你往往想按API路径、视图类甚至查询参数动态区分规则。
真正起作用的是继承
并重写
:它返回
表示不限流,返回字符串则作为缓存键参与计数。比如按URL路径+用户ID组合限流:
注意:
必须和
里的键名一致,否则配置不加载。
立即学习
“
Python免费学习笔记(深入)
”;
如何在不同视图中启用不同限流策略
DRF不支持在
里为每个视图单独配rate,得靠视图层显式声明。最灵活的方式是用
属性,而不是全局配置。
或
子类:直接设
:可在类属性设,也可在具体
方法上用
需要临时关闭限流?返回
从
即可,比注释代码更可控
别把所有视图都塞进同一个
,否则修改速率要重启服务;拆成细粒度
(如
、
),再在
里分别配
。
Django 4下Redis缓存后端是限流稳定性的关键
DRF的
底层依赖Django的
,而Django 4默认的
在多进程部署(如gunicorn多worker)时完全失效——每个worker维护独立内存缓存,限流形同虚设。
Python 3.14.3
微软官方的 Python 扩展,是 VS Code 安装量最高的扩展(209M+)。集成 IntelliSense(通过 Pylance)、调试(通过 Python Debugger)、代码检查、格式化、重构和单元测试等功能。支持 Jupyter Notebook、虚拟环境管理和多 Python 版本切换。
下载
必须改用Redis:
同时确认已安装
,且
包含
。漏掉任一环节,
会静默退化为不生效,连错误日志都不抛。
调试限流失败时优先检查
返回值和缓存命中
限流没反应,90%情况是
返回了
或空字符串。加一行日志验证:
生产环境建议用
并确保日志级别够低。另外,用
手动查键是否存在:
如果完全查不到,说明缓存没写入——大概率是缓存配置未生效,或者
被异常中断(比如Redis连接超时但没报错)。
动态限流真正的复杂点不在写法,而在“什么时候该放行、什么时候该拦截”的业务判断。比如搜索接口要对高频关键词限流,就得在
里解析
,还要考虑空值、编码、SQL注入风险——这些逻辑一旦写错,限流就变成漏洞。
SimpleRateThrottleget_cache_keyDEFAULT_THROTTLE_RATESAnonRateThrottleUserRateThrottleuser.idSimpleRateThrottleget_cache_keyNoneclass PathUserThrottle(SimpleRateThrottle):
scope = 'path_user'
def get_cache_key(self, request, view):
if not request.user.is_authenticated:
return None # 匿名用户走另一套规则
return f'user_{request.user.id}_{request.path_info}'scopeDEFAULT_THROTTLE_RATESsettings.pythrottle_classesAPIViewGenericAPIViewthrottle_classes = [PathUserThrottle]ViewSetaction@action(throttle_classes=[...])Noneget_cache_keyscopescope'login''search'settings.pyDEFAULT_THROTTLE_RATES = {'login': '5/min', 'search': '20/hour'}SimpleRateThrottlecacheLocMemCacheCACHES = {
'default': {
'BACKEND': 'django_redis.cache.RedisCache',
'LOCATION': 'redis://127.0.0.1:6379/1',
'OPTIONS': {'CLIENT_CLASS': 'django_redis.client.DefaultClient'},
}
}
django-redisINSTALLED_APPSdjango_redisthrottleget_cache_keyget_cache_keyNonedef get_cache_key(self, request, view):
key = f'user_{request.user.id}_{request.path_info}'
print(f'[Throttle] cache key: {key}') # 仅开发环境用
return key
logging.debugredis-cliredis-cli -n 1 keys "throttle_*"
cache.setget_cache_keyrequest.GET.get('q')