瀏覽代碼

修复FeignCircuitBreakerInitializer因Spring上下文刷新导致异常问题;修复特定场景下无法获取客户端真实IP问题;

Woody 3 周之前
父節點
當前提交
b52db1e182

+ 26 - 12
framework-base/src/main/java/com/chelvc/framework/base/util/HttpUtils.java

@@ -60,7 +60,7 @@ public final class HttpUtils {
      * 客户端主机地址请求头数组
      */
     private static final String[] REQUEST_ADDRESS_HEADER_ARRAY = new String[]{
-            "X-Real-IP", "X-Forwarded-For", "Proxy-Client-IP", "WL-Proxy-Client-IP"
+            "x-original-forwarded-for", "x-real-ip", "x-forwarded-for", "proxy-client-ip", "wl-proxy-client-ip"
     };
 
     private HttpUtils() {
@@ -182,24 +182,38 @@ public final class HttpUtils {
      * @return 请求客户端主机地址
      */
     public static String getHost(@NonNull HttpServletRequest request) {
-        // 获取请求主机地址
-        String ip = null;
+        // 从请求头获取客户端地址
+        String host = null;
         for (String header : REQUEST_ADDRESS_HEADER_ARRAY) {
-            if (StringUtils.notEmpty(ip = request.getHeader(header)) && !HostUtils.UNKNOWN_ADDRESS.equals(ip)) {
-                break;
+            String ip = request.getHeader(header);
+            if (StringUtils.isEmpty(ip) || HostUtils.UNKNOWN_ADDRESS.equals(ip)) {
+                continue;
+            }
+
+            // 优先获取公网地址,否则获取第一个非空地址
+            if (!HostUtils.isIntranet(ip)) {
+                return ip;
+            } else if (StringUtils.isEmpty(host)) {
+                host = ip;
             }
         }
-        if (StringUtils.isEmpty(ip)) {
-            ip = request.getRemoteAddr();
+
+        // 通过默认方式获取客户端地址
+        if (StringUtils.isEmpty(host)) {
+            host = request.getRemoteAddr();
         }
 
         // 如果地址存在多个则获取第一个
-        int separatorIndex = ip.indexOf(',');
-        if (separatorIndex > -1) {
-            ip = ip.substring(0, separatorIndex);
+        if (host.indexOf(',') > 0) {
+            String[] ips = host.split(",");
+            for (String ip : ips) {
+                if (!HostUtils.isIntranet(ip)) {
+                    return ip;
+                }
+            }
+            host = ips[0];
         }
-
-        return HostUtils.DEFAULT_LOCAL_ADDRESS_IPV6.equals(ip) ? HostUtils.LOCAL_ADDRESS : ip;
+        return HostUtils.DEFAULT_LOCAL_ADDRESS_IPV6.equals(host) ? HostUtils.LOCAL_ADDRESS : host;
     }
 
     /**

+ 28 - 0
framework-common/src/main/java/com/chelvc/framework/common/util/HostUtils.java

@@ -5,6 +5,7 @@ import java.net.InetAddress;
 import java.net.NetworkInterface;
 import java.util.Enumeration;
 
+import com.chelvc.framework.common.model.Ip;
 import lombok.extern.slf4j.Slf4j;
 
 /**
@@ -40,6 +41,13 @@ public final class HostUtils {
      */
     public static final String DEFAULT_LOCAL_ADDRESS_IPV6 = "0:0:0:0:0:0:0:1";
 
+    /**
+     * 内网网段地址列表
+     */
+    private static final Ip[] INTRANET_ADDRESSES = new Ip[]{
+            new Ip("10.0.0.0/8"), new Ip("172.16.0.0/12"), new Ip("192.168.0.0/16")
+    };
+
     static {
         LOCAL_ADDRESS = getLocalhostAddress();
     }
@@ -70,4 +78,24 @@ public final class HostUtils {
         }
         return DEFAULT_LOCAL_ADDRESS;
     }
+
+    /**
+     * 判断IP是否属于内网
+     *
+     * @param host IP地址
+     * @return true/false
+     */
+    public static boolean isIntranet(String host) {
+        if (StringUtils.isEmpty(host)) {
+            return false;
+        } else if (DEFAULT_LOCAL_ADDRESS.contentEquals(host) || DEFAULT_LOCAL_ADDRESS_IPV6.contentEquals(host)) {
+            return true;
+        }
+        for (Ip ip : INTRANET_ADDRESSES) {
+            if (ip.matches(host)) {
+                return true;
+            }
+        }
+        return false;
+    }
 }

+ 4 - 2
framework-feign-circuitbreaker/src/main/java/com/chelvc/framework/feign/circuitbreaker/FeignCircuitBreakerInitializer.java

@@ -49,8 +49,10 @@ public class FeignCircuitBreakerInitializer implements SpringApplicationRunListe
     private static FeignCircuitBreaker MAIN_BREAKER;
 
     public FeignCircuitBreakerInitializer(SpringApplication application, String[] args) {
-        Class<?> main = application.getMainApplicationClass();
-        MAIN_BREAKER = main.getAnnotation(FeignCircuitBreaker.class);
+        if (MAIN_BREAKER == null) {
+            Class<?> main = application.getMainApplicationClass();
+            MAIN_BREAKER = ObjectUtils.ifNull(main, clazz -> clazz.getAnnotation(FeignCircuitBreaker.class));
+        }
     }
 
     /**