文章目录
- 基于Spring MVC的客户端真实IP获取方案解析
- 概述
- 核心方法解析
- 代码实现
- 工作流程
- IP获取优先级策略
- IP有效性验证
- 异常处理与日志
- 使用场景
- 注意事项
- 扩展建议
基于Spring MVC的客户端真实IP获取方案解析
概述
在Web应用开发中,准确获取客户端真实IP地址是常见的需求。本文介绍一个基于Spring MVC实现的客户端IP获取方案ClientIpController
,该方案支持多种代理场景下的IP识别,并包含完善的校验机制。
核心方法解析
代码实现
/**
* 获取客户端公网IP
*
* @author xdr630
*/
@RestController
public class ClientIpController {
private static final Logger LOGGER = LoggerFactory.getLogger(KocaClientIpController.class);
@GetMapping("/getRemoteIp")
@ResponseBody
public String getClientIp(HttpServletRequest request) {
String clientIp = null;
try {
String xForwardedFor = request.getHeader("X-Forwarded-For");
if (xForwardedFor != null && !xForwardedFor.isEmpty() && !"unknown".equalsIgnoreCase(xForwardedFor)) {
// X-Forwarded-For:Squid 服务代理,X-Forwarded-For 可能包含多个 IP,取第一个非空的 IP
clientIp = xForwardedFor.split(",")[0].trim();
}
if (clientIp == null || clientIp.isEmpty() || "unknown".equalsIgnoreCase(clientIp)) {
// Proxy-Client-IP:apache 服务代理
clientIp = request.getHeader("Proxy-Client-IP");
}
if (clientIp == null || clientIp.isEmpty() || "unknown".equalsIgnoreCase(clientIp)) {
// WL-Proxy-Client-IP:weblogic 服务代理
clientIp = request.getHeader("WL-Proxy-Client-IP");
}
if ((clientIp == null || clientIp.isEmpty() || "unknown".equalsIgnoreCase(clientIp))) {
// X-Real-IP:nginx服务代理
clientIp = request.getHeader("X-Real-IP");
}
if (clientIp == null || clientIp.isEmpty() || "unknown".equalsIgnoreCase(clientIp)) {
clientIp = request.getRemoteAddr();
}
if (clientIp != null && !clientIp.isEmpty()) {
clientIp = clientIp.split(",")[0];
}
if (!isValidIPv4(clientIp)) {
LOGGER.warn("无效的客户端 IP: {}", clientIp);
// 在浏览器端显示返回null
clientIp = "null";
}
} catch (Exception e) {
LOGGER.error("获取客户端公网IP失败", e);
throw new RuntimeException(e);
}
return clientIp;
}
private boolean isValidIPv4(String ip) {
String ipv4Regex = "^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$";
return Pattern.compile(ipv4Regex).matcher(ip).matches();
}
}
工作流程
-
多级代理支持:依次检查以下请求头
X-Forwarded-For
:处理Squid等代理的逗号分隔IPProxy-Client-IP
:Apache代理WL-Proxy-Client-IP
:WebLogic代理X-Real-IP
:Nginx代理
-
最终回退机制
clientIp = request.getRemoteAddr();
- 结果处理
- 取首个有效IP段
- IPv4格式校验
- 异常IP返回"null"字符串
IP获取优先级策略
优先级 | Header名称 | 代理类型 |
---|---|---|
1 | X-Forwarded-For | 通用代理/Squid |
2 | Proxy-Client-IP | Apache |
3 | WL-Proxy-Client-IP | WebLogic |
4 | X-Real-IP | Nginx |
5 | getRemoteAddr() | 直接连接 |
IP有效性验证
采用正则表达式校验IPv4格式:
^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$
异常处理与日志
- WARN级别日志:记录无效IP格式
- ERROR级别日志:捕获处理异常
- 异常转换:将检查异常转为RuntimeException
使用场景
- 反向代理架构下的真实IP获取
- 客户端地理位置服务
- 访问频率控制
- 安全审计日志
注意事项
- 代理链中的首个IP可能不可信(需结合安全策略)
- 不支持IPv6地址(需扩展正则校验)
- 生产环境建议添加速率限制
- 重要场景建议结合XFF白名单验证
扩展建议
- 增加IPv6支持
- 添加可信代理IP列表验证
- 集成缓存机制防止滥用
- 补充单元测试覆盖边界情况
该方案提供了可靠的客户端IP获取实现,开发人员应根据实际网络架构调整header的检查顺序,并在安全敏感场景中补充额外的验证逻辑。