部署在Cloud Run的Spring Boot应用如何获取IPv4地址?
解决Cloud Run上Spring Boot应用获取IPv4地址的问题
核心原因
Cloud Run的网络架构基于IPv6构建,前端负载均衡会将用户的IPv4地址转换为::ffff:x.x.x.x这类IPv6映射格式,注入到X-FORWARDED-FOR请求头中。你之前添加的JVM参数-Djava.net.preferIPv4Stack=true和-Djava.net.preferIPv4Addresses=true只控制应用自身的网络栈行为,无法改变反向代理注入的请求头内容,所以无效。
可行解决方案
1. 解析IPv6映射的IPv4地址
直接从X-FORWARDED-FOR的IPv6格式中提取IPv4部分,工具类示例:
public static String getIPv4FromForwardedHeader(String forwardedFor) { if (forwardedFor == null) return null; // 处理IPv4映射的IPv6地址(前缀为::ffff:) if (forwardedFor.startsWith("::ffff:")) { return forwardedFor.substring(7); } // 直接返回标准IPv4地址(如果存在) if (forwardedFor.contains(".") && !forwardedFor.contains(":")) { return forwardedFor; } return forwardedFor; }
调用方式:
String clientIp = getIPv4FromForwardedHeader(req.getHeader("X-FORWARDED-FOR"));
2. 处理多代理场景的IP列表
如果X-FORWARDED-FOR包含多个IP(比如经过多层代理),取第一个非本地地址后再解析:
public static String extractClientIPv4(String forwardedFor) { if (forwardedFor == null) return null; String[] ips = forwardedFor.split(","); for (String ip : ips) { String trimmedIp = ip.trim(); // 跳过本地/内网IP,提取真实用户IP if (!trimmedIp.startsWith("127.") && !trimmedIp.startsWith("192.168.") && !trimmedIp.startsWith("10.")) { return getIPv4FromForwardedHeader(trimmedIp); } } return null; }
3. 移除无效的JVM参数
既然-Djava.net.preferIPv4Stack=true和-Djava.net.preferIPv4Addresses=true对请求头无影响,建议从启动命令中移除,避免冗余配置。
内容的提问来源于stack exchange,提问作者Srinivasan
相关产品推荐
相关产品推荐

