public static String getClientIp(HttpServletRequest request) {
String ip = request.getHeader("X-Forwarded-For");
if (isValid(ip)) return ip.split(",")[0].trim(); // 取第一個非代理 IP
ip = request.getHeader("X-Real-IP");
if (isValid(ip)) return ip;
ip = request.getHeader("Proxy-Client-IP");
if (isValid(ip)) return ip;
ip = request.getHeader("WL-Proxy-Client-IP");
if (isValid(ip)) return ip;
ip = request.getHeader("HTTP_CLIENT_IP");
if (isValid(ip)) return ip;
ip = request.getHeader("HTTP_X_FORWARDED_FOR");
if (isValid(ip)) return ip;
return request.getRemoteAddr(); // 最後兜底
}
private static boolean isValid(String ip) {
return ip != null && !ip.isEmpty() && !"unknown".equalsIgnoreCase(ip);
}
X-Forwarded-For:標準代理頭,格式 client, proxy1, proxy2,首個為真實客戶端。X-Real-IP:Nginx proxy_set_header X-Real-IP $remote_addr; 設置的單一真實 IP。getRemoteAddr():直連時返回客戶端 IP,經代理時返回代理服務器 IP。proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
RemoteIpValve 解析頭並覆蓋 request.remoteAddr,後續 request.getRemoteAddr() 即為真實 IP,無需手動解析。同一廣播域可用 nbtstat -A <ip> 或 ARP 表解析,跨路由不可行。生產環境勿依賴 MAC 做身份識別。