本文目录导读:

- 标准Servlet(Spring MVC/普通Web应用)
- Spring Boot WebFlux(响应式编程)
- Spring Cloud Gateway(过滤器方式)
- 使用Spring AOP统一处理
- 处理IPv6地址(可选)
- Nginx配置配合(关键)
- Spring Boot application.yml配置
- 完整工具类(包含边界处理)
- 注意事项
在Java中获取客户端真实IP需要根据不同的技术栈采用不同的方法,以下是几种常见场景的实现方式:
标准Servlet(Spring MVC/普通Web应用)
import javax.servlet.http.HttpServletRequest;
public class IpUtils {
public static String getClientIp(HttpServletRequest request) {
String ip = request.getHeader("X-Forwarded-For");
if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_X_FORWARDED_FOR");
}
if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_X_FORWARDED");
}
if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_X_CLUSTER_CLIENT_IP");
}
if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_CLIENT_IP");
}
if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_FORWARDED_FOR");
}
if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_FORWARDED");
}
if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_VIA");
}
if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
// 处理多级代理的情况(如:X-Forwarded-For: client, proxy1, proxy2)
if (ip != null && ip.contains(",")) {
ip = ip.split(",")[0].trim();
}
return ip;
}
}
使用示例:
@RestController
public class IpController {
@GetMapping("/get-ip")
public String getIp(HttpServletRequest request) {
return "客户端IP: " + IpUtils.getClientIp(request);
}
}
Spring Boot WebFlux(响应式编程)
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
@Component
public class IpWebFluxUtils {
public static Mono<String> getClientIp(ServerWebExchange exchange) {
return Mono.justOrEmpty(exchange.getRequest().getHeaders()
.getFirst("X-Forwarded-For"))
.filter(ip -> !ip.isEmpty() && !"unknown".equalsIgnoreCase(ip))
.map(ip -> ip.split(",")[0].trim())
.switchIfEmpty(
Mono.justOrEmpty(exchange.getRequest().getHeaders()
.getFirst("Proxy-Client-IP"))
)
.switchIfEmpty(
Mono.justOrEmpty(exchange.getRequest().getHeaders()
.getFirst("WL-Proxy-Client-IP"))
)
.switchIfEmpty(
Mono.just(exchange.getRequest().getRemoteAddress()
.map(address -> address.getAddress().getHostAddress())
.orElse(""))
);
}
}
使用示例:
@RestController
public class IpWebFluxController {
@GetMapping("/get-ip")
public Mono<String> getIp(ServerWebExchange exchange) {
return IpWebFluxUtils.getClientIp(exchange);
}
}
Spring Cloud Gateway(过滤器方式)
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
@Component
public class IpGatewayFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
String ip = getIpFromRequest(request);
// 将IP添加到请求头中,传递给下游服务
ServerHttpRequest modifiedRequest = request.mutate()
.header("X-Real-IP", ip)
.build();
ServerWebExchange modifiedExchange = exchange.mutate()
.request(modifiedRequest)
.build();
return chain.filter(modifiedExchange);
}
private String getIpFromRequest(ServerHttpRequest request) {
String ip = request.getHeaders().getFirst("X-Forwarded-For");
if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeaders().getFirst("X-Real-IP");
}
if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddress() != null
? request.getRemoteAddress().getAddress().getHostAddress()
: "";
}
if (ip != null && ip.contains(",")) {
ip = ip.split(",")[0].trim();
}
return ip;
}
@Override
public int getOrder() {
return Integer.MIN_VALUE;
}
}
使用Spring AOP统一处理
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
@Aspect
@Component
public class IpAspect {
@Before("execution(* com.yourpackage.controller.*.*(..))")
public void setIpToThreadLocal() {
ServletRequestAttributes attributes =
(ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if (attributes != null) {
HttpServletRequest request = attributes.getRequest();
String ip = IpUtils.getClientIp(request);
// 存储到ThreadLocal或MDC中,供后续使用
IpContextHolder.setIp(ip);
}
}
}
处理IPv6地址(可选)
public static String getRealIp(HttpServletRequest request) {
String ip = getClientIp(request);
// 处理IPv6本地地址
if (ip != null && ip.startsWith("[") && ip.endsWith("]")) {
ip = ip.substring(1, ip.length() - 1);
}
// IPv6环回地址
if ("0:0:0:0:0:0:0:1".equals(ip) || "::1".equals(ip)) {
ip = "127.0.0.1";
}
return ip;
}
Nginx配置配合(关键)
需要在Nginx中添加配置,确保真实IP能传递到后端:
server {
listen 80;
server_name example.com;
location / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_pass http://your-backend;
}
}
Spring Boot application.yml配置
server: # 如果使用反向代理,需要配置信任的代理 forward-headers-strategy: framework # 或者 # forward-headers-strategy: native
完整工具类(包含边界处理)
import javax.servlet.http.HttpServletRequest;
import java.net.InetAddress;
import java.net.UnknownHostException;
public class IpUtils {
private static final String[] IP_HEADERS = {
"X-Forwarded-For",
"Proxy-Client-IP",
"WL-Proxy-Client-IP",
"HTTP_X_FORWARDED_FOR",
"HTTP_X_FORWARDED",
"HTTP_X_CLUSTER_CLIENT_IP",
"HTTP_CLIENT_IP",
"HTTP_FORWARDED_FOR",
"HTTP_FORWARDED",
"HTTP_VIA",
"REMOTE_ADDR"
};
public static String getClientIp(HttpServletRequest request) {
String ip = null;
for (String header : IP_HEADERS) {
ip = request.getHeader(header);
if (isValidIp(ip)) {
break;
}
}
if (ip == null || ip.isEmpty()) {
ip = request.getRemoteAddr();
}
// 处理多级代理
if (ip != null && ip.contains(",")) {
ip = ip.split(",")[0].trim();
}
// 处理IPv6
ip = normalizeIp(ip);
return ip;
}
private static boolean isValidIp(String ip) {
return ip != null && !ip.isEmpty() && !"unknown".equalsIgnoreCase(ip);
}
private static String normalizeIp(String ip) {
if (ip == null) return null;
// 处理IPv6环回地址
if ("0:0:0:0:0:0:0:1".equals(ip) || "::1".equals(ip)) {
return "127.0.0.1";
}
// 处理IPv6格式
if (ip.startsWith("[") && ip.endsWith("]")) {
ip = ip.substring(1, ip.length() - 1);
}
// 处理IPv4-mapped IPv6地址
if (ip.startsWith("::ffff:")) {
ip = ip.substring(7);
}
return ip;
}
public static boolean isInternalIp(String ip) {
try {
InetAddress inet = InetAddress.getByName(ip);
return inet.isSiteLocalAddress() || inet.isLoopbackAddress();
} catch (UnknownHostException e) {
return false;
}
}
}
注意事项
- 安全性:不要完全信任HTTP头中的IP,尤其是
X-Forwarded-For可以被伪造 - 性能:避免在频繁调用的方法中重复解析IP
- 代理环境:确保反向代理配置了正确的请求头传递
- IPv6兼容:现代应用需要考虑IPv6的兼容性
- 容器环境:在Docker、Kubernetes等环境中,可能需要特殊处理
选择哪种方式取决于你的具体应用场景和技术栈,最常用的是第一种标准Servlet方式,配合Nginx等反向代理的配置。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播