核心是实时拦截、精准识别、无损更新:用Redis存黑名单(支持分zone键、设过期时间),在access阶段拦截(OpenResty用access_by_lua_block,Spring Cloud Gateway用高优先级GlobalFilter),精准提取真实IP并支持CIDR匹配,复用连接池避免性能拖累。

网关层的黑名单动态封禁隔离,核心是“实时拦截 + 精准识别 + 无损更新”,不是简单加一条 deny 规则就完事。重点不在封,而在封得准、解得快、不影响正常流量。
用 Redis 存名单,别用配置文件硬写
配置文件 reload 有延迟、难回滚、不支持热更新。生产必须用外部存储:
- 单业务统一管控:用 Redis SET,键如 ip_blacklist,查
SMISMEMBER ip_blacklist 192.168.1.100,O(1) 响应 - 多业务共用网关:按 zone 分 key,比如 admin_zone:blacklist 或 api_v1:blacklist:202609,避免 A 业务封 IP 影响 B 业务
- 所有 key 必须设过期时间(
SETEX或后续EXPIRE),暴力探测建议封 5 分钟,爬虫类可设 2 小时,杜绝误封永久化
拦截阶段必须在 access 阶段完成
封禁动作要卡在请求发往后端之前,否则等于白干:
- OpenResty 场景:死守 access_by_lua_block,绝不能写进
content_by_lua_block—— 后者已调用 upstream,连接开销白费,封禁无效 - Spring Cloud Gateway 场景:自定义 GlobalFilter,order 设为 -1 或更低,确保早于路由转发执行;不要塞进 default-filters,容易因配置层级缺失导致不生效
- Golang 网关:用闭包中间件,在
http.ServeMux或路由 handler 前插入,提取真实 IP 后立即比对,命中即http.Error(w, "Forbidden", 403)
IP 提取和匹配要兜底且兼容
真实客户端 IP 容易被伪造或嵌套,不能只信 RemoteAddr:
- 优先读 X-Forwarded-For(取最左非私有地址),再 fallback 到 X-Real-IP,最后才用
RemoteAddr并手动剥离端口:strings.Split(req.RemoteAddr, ":")[0] - 支持 CIDR 网段匹配(如 10.0.0.0/8 或 2001:db8::/32),Golang 用
net.ParseCIDR,Lua 可用lua-resty-iputils,别只做字符串前缀匹配 - 本地调试流量(127.0.0.1、::1)建议白名单放行,避免运营操作把自己锁在外面
连接与性能不能拖后腿
黑名单查得再快,Redis 连不上或每次新建连接,照样拖垮网关:
- OpenResty:复用
lua-resty-redis连接池,设置set_timeout和合理 pool size,避免 TIME_WAIT 拥塞 - Spring Cloud Gateway:用
ReactiveRedisTemplate,走响应式 pipeline,别用阻塞式 Jedis - 高频读+低频写场景:Golang 用
sync.RWMutex + map[string]bool,初始化预分配容量;写操作仅在管理接口(如/admin/blacklist/add)中加锁,校验逻辑全程无锁读











