直接用flask-limiter最省事,它已内置处理代理穿透、并发竞争、ipv6和多进程失效;不能仅依赖request.remote_addr,因反代后其值恒为127.0.0.1或内网地址,需通过可信代理范围校验x-forwarded-for链并取首个非代理ip作为限流key。

直接用 flask-limiter,别自己手写计数逻辑——它已处理代理穿透、并发竞争、IPv6 和多进程失效这些坑,硬搞反而容易漏掉真实攻击源。
为什么不能只用 request.remote_addr 提取 IP
在 Nginx、Cloudflare 或其他反向代理后,request.remote_addr 永远是 127.0.0.1 或内网地址,所有请求会被当成同一个 IP 限流,导致误杀;而盲目读 X-Forwarded-For 又会被伪造 header 绕过。
必须显式定义可信代理范围,并从 X-Forwarded-For 链中取第一个非代理 IP:
from flask import request
<p>def get_ipaddr():
trusted_proxies = {"192.168.10.0/24", "10.0.0.5"} # 填你实际的反代 IP 段或地址
ip = request.remote_addr
if request.headers.get("X-Forwarded-For"):
ips = [i.strip() for i in request.headers["X-Forwarded-For"].split(",")]
for i in reversed(ips):
if i not in trusted_proxies:
ip = i
break
return ip
</p>
- 这个函数必须传给
Limiter的key_func参数,否则限流 key 会错 - 如果部署在 Cloudflare 后,
trusted_proxies应包含 Cloudflare 的全部 IP 段(官方列表可查) - 返回值不能为
None,建议兜底返回"unknown"字符串
@limiter.limit 的速率字符串怎么写才不被绕过
格式是 "<number> per <time_unit>"</time_unit></number>,拼写、空格、单复数全敏感。写错就等于没限——比如 "5/min" 完全无效,"5 per minutes" 会被解析成每秒级粒度,实际效果可能比预期松 60 倍。
- 正确写法:
"10 per minute"、"100 per day"、"1 per second" - 支持的时间单位只有:
second、minute、hour、day、month、year(没有sec或hr) - 多个策略可叠加:
@limiter.limit("5 per minute", "100 per day"),任一超限即返回 429 - 对登录接口这类高危路径,建议加更严策略,例如
"3 per minute"防暴力破解
生产环境 Redis 配置不生效却完全无报错
flask-limiter 默认用内存存储(memory://),多进程下计数器不共享,且连接 Redis 失败时会静默降级——你看到服务正常跑着,其实限流根本没起作用。
- 必须显式指定
storage_uri,不能依赖默认值:redis://:password@127.0.0.1:6379/1 - 密码含特殊字符(如
@、/)要 URL 编码,否则连接失败 - 手动验证 Redis 连通性:
redis.from_url("redis://localhost:6379/1").ping()应返回True - 避免对
/healthz、/static、OPTIONS请求限流,用exempt_when显式跳过
最常被忽略的是:限流 key 的构造逻辑和 Redis 连接验证必须上线前实测,不能只靠本地调试——代理链路、容器网络、Redis 权限这三处最容易出 silent failure。
大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!











