PHP用Redis限制爬虫频率的核心是基于IP的轻量原子计数与实时拦截:通过Nginx透传真实IP并多层校验获取可信IP,采用固定窗口(如rate:ip:{ip}:2026081709)或滑动窗口(List存时间戳)策略,配合INCR/EXPIRE原子操作与429响应,同时设置Redis超时降级和Nginx前置限流形成分层防护。

PHP用Redis限制爬虫访问频率,核心是识别异常请求行为并快速拦截,不依赖前端或用户登录态,直接基于IP或请求特征做实时计数与判定。关键在于轻量、原子、可降级,避免因Redis故障拖垮整个接口。
识别真实客户端IP防伪造
爬虫常伪造X-Forwarded-For或X-Real-IP头,需结合Nginx透传与PHP多层校验获取可信IP:
- Nginx配置中加:
set_real_ip_from 10.0.0.0/8;(按实际内网段调整),并启用real_ip_header X-Forwarded-For; - PHP中统一用封装函数获取:
get_client_ip(),优先取$_SERVER['HTTP_X_REAL_IP'],其次$_SERVER['HTTP_X_FORWARDED_FOR'](取第一个非内网IP),最后 fallback 到$_SERVER['REMOTE_ADDR'] - 对明显代理IP段(如已知数据中心段、云厂商出口段)可额外打标,提高限流敏感度
固定窗口计数器(推荐初用)
实现简单、性能高、Redis压力小,适合大多数防爬场景(如单IP每分钟最多30次):
- Key设计为:
rate:ip:{ip}:2026081709(含年月日小时,便于人工排查) - 每次请求执行:
$redis->incr($key),若返回值为1,立即$redis->expire($key, 3600) - 判断逻辑:
if ($redis->get($key) > 30) { http_response_code(429); exit('Too many requests'); } - 注意:不要用
SET覆盖计数,否则会清除TTL;用INCR或INCRBY可保留过期时间
增强型滑动窗口(应对高频绕过)
当发现爬虫在窗口边界集中刷量(如每分钟第59秒狂发请求),可升级为基于List的滑动窗口,精确控制“最近60秒”内请求数:
立即学习“PHP免费学习笔记(深入)”;
- Key为:
sliding:ip:{ip},数据类型为List - 每次请求先
$redis->lPush($key, time()),再$redis->lTrim($key, 0, 99)(最多存100个时间戳) - 用
$redis->lRange($key, 0, -1)取出全部时间戳,遍历过滤出time() - $ts 的数量 - 若数量 ≥ 50,执行
$redis->set("block:ip:{$ip}", 1, ['EX' => 300])封禁5分钟 - 此方式Redis命令稍多,建议配合连接池与超时设置(如
timeout=0.1)防止阻塞
配合Nginx做前置拦截(双重防护)
PHP层限流是兜底,真正高效的是在Nginx接入层就拦住大部分恶意流量:
- 用OpenResty + Lua脚本,在
access_by_lua_file阶段查Redis黑名单:if redis:get("block:ip:" .. ip) == "1" then ngx.exit(403) end - 同时对疑似爬虫的User-Agent(如
python-requests、curl/7.、无Referer+无Cookie)单独设更严阈值 - 把Nginx的
limit_req作为第一道防线(例如rate=2r/s),PHP Redis限流作为第二道(例如rate=30/m),形成分层防御
不复杂但容易忽略:所有Redis操作必须设超时和错误降级——连接失败时记录warn日志但放行请求,绝不能让Redis不可用导致全站500。



















