跳转到主内容
新派编程网 - 新潮编程理念,全新技术课堂!

Django 4如何实现RESTful API动态限流_Python配合DRF内置Throttle组件控制频率

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

相关文章