应优先通过检查x-forwarded-for、x-real-ip、cf-connecting-ip等http头获取真实客户端ip,而非直接使用request.client.host;再利用redis zset实现滑动窗口限流,以时间戳为score记录每次请求,通过zremrangebyscore和zcard原子统计窗口内请求数,并设置key过期避免内存泄漏。

可以通过记录IP访问时间戳并设置滑动窗口或固定周期计数,结合Redis或文件存储实现限流。核心是识别客户端真实IP、设定合理阈值、及时清理过期记录。
获取客户端真实IP地址
直接用$_SERVER['REMOTE_ADDR']可能拿到代理或CDN的IP,需逐级检查HTTP_X_FORWARDED_FOR、HTTP_X_REAL_IP等头信息,取最左非内网IP:
- 先过滤私有IP段(127.0.0.1、10.0.0.0/8、172.16.0.0/12、192.168.0.0/16、::1等)
- 对X-Forwarded-For按逗号分割,取第一个合法公网IP
- 生产环境建议配合Nginx配置real_ip_header和set_real_ip_from统一处理
使用Redis实现高频限流(推荐)
利用Redis的INCR和EXPIRE命令原子性完成计数与过期设置:
- 键名格式如:rate_limit:192.168.1.100:60(IP+时间窗口秒数)
- 每次请求执行:INCR key,若返回值为1则立即EXPIRE key 60
- 若返回值 > 阈值(如100次/分钟),返回429状态码并中断后续逻辑
- 注意:Redis连接需复用,避免每次新建连接开销
降级方案:基于文件的轻量限流
无Redis时可用文件存储,但仅适合低并发场景(需加锁防竞态):
- 以IP哈希值命名文件(如ip_2a3f.lock),内容存JSON:{"count":5,"last_time":1717023456}
- 读写前用flock($fp, LOCK_EX)加独占锁
- 检查last_time是否在当前窗口内,是则count++,否则重置为1并更新last_time
- 超限时抛出异常或返回拦截响应,避免继续执行业务逻辑
识别并区分爬虫流量
单靠IP限流不够精准,建议叠加User-Agent和请求行为判断:
- 检查$_SERVER['HTTP_USER_AGENT']是否含常见爬虫标识(如Googlebot、Baiduspider、curl、python-requests)
- 对匹配的UA,默认启用更严格阈值(如30次/分钟),或直接拒绝无Referer+无Cookie的请求
- 可结合访问路径分析:高频请求/api/、/wp-json/、无HTML后缀路径,倾向判定为爬虫
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











