直接用HandlerInterceptor+RedisTemplate可实现IP黑名单拦截,但必须正确处理IP提取(优先x-forwarded-for并校验格式)、Redis选Set结构(SISMEMBER高效判断存在性)、路径排除(如/actuator/**等)三处,否则会漏拦或误拦。

直接用 HandlerInterceptor + RedisTemplate 就能跑通,但必须处理好 IP 提取、Redis 数据结构选型、原子性校验这三处,否则上线后会漏拦或误拦。
IP 地址提取要防代理穿透
直接用 request.getRemoteAddr() 在有 Nginx 或云 WAF 的场景下几乎必然拿到的是 127.0.0.1 或内网地址。必须按标准顺序读取头信息:
- 优先取
x-forwarded-for,截取第一个非unknown的 IP(注意可能被伪造,仅用于风控场景) - fallback 到
x-real-ip(Nginx 显式透传时更可信) - 最后才用
getRemoteAddr()
别写成单层 if-else 判断,要用循环拆分 x-forwarded-for 字符串并逐个校验格式,否则遇到 "1.1.1.1, 2.2.2.2, 127.0.0.1" 这类值会误判。
Redis 存储结构选 Set 而不是 String 或 Hash
黑名单本质是「存在性判断」,不是计数也不是带元数据的记录。用 Set 最合适:
-
SISMEMBER ip:blacklist 192.168.1.100是 O(1) 时间复杂度 - 避免用
String存 CSV(如"192.168.1.100,10.0.0.5"),每次都要GET+split,并发高时 Redis 带宽和应用 CPU 都吃紧 - 不用
Hash存(如HGETALL ip:blacklist),全量拉取再遍历,数据量稍大就卡顿
添加 IP 时用 SADD ip:blacklist 192.168.1.100,删除用 SREM,清空用 DEL ip:blacklist —— 所有操作原生支持,无需 Lua 脚本。
拦截器注册时路径匹配要避开静态资源和健康检查
别一股脑拦截 /**,否则 /actuator/health、/swagger-ui.html、/favicon.ico 全被拦,运维和前端联调直接崩溃:
- 在
addInterceptors()中明确 excludePathPatterns:/actuator/**、/webjars/**、/v3/api-docs/**、/swagger-ui/** - 如果用了 Spring Security,确保拦截器顺序在
SecurityFilterChain之后(或明确用@Order(Ordered.HIGHEST_PRECEDENCE)控制) - 测试时 curl 一个被排除的路径,确认响应码是 200 而不是 -1 或 403
最常被忽略的是:Spring Boot 3.x 默认禁用 TRACE 和 HEAD 等方法的自动映射,但黑名单拦截器若没显式跳过这些 method,可能把健康探针当成恶意请求干掉。











