From 41d85abf23c123e948b1a585c413f5a0a29a504f Mon Sep 17 00:00:00 2001
From: bluejay <253316343@qq.com>
Date: 星期二, 08 四月 2025 09:05:49 +0800
Subject: [PATCH] gateway 根据matedate转发到本地服务

---
 aps-gateway/src/main/java/com/aps/gateway/config/loadBalancer/GrayLoadBalancer.java                     |   10 +++
 aps-gateway/src/main/java/com/aps/gateway/config/loadBalancer/GrayReactiveLoadBalancerClientFilter.java |   99 +++++++++++++++++++++++++++++++++
 aps-gateway/src/main/java/com/aps/gateway/config/loadBalancer/VersionGrayLoadBalancer.java              |   60 ++++++++++++++++++++
 aps-gateway/pom.xml                                                                                     |   11 +++
 4 files changed, 179 insertions(+), 1 deletions(-)

diff --git a/aps-gateway/pom.xml b/aps-gateway/pom.xml
index d5b6905..4e0cb1f 100644
--- a/aps-gateway/pom.xml
+++ b/aps-gateway/pom.xml
@@ -82,7 +82,16 @@
             <artifactId>springdoc-openapi-starter-webflux-ui</artifactId>
             <version>${springdoc.version}</version>
         </dependency>
-
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>cn.hutool</groupId>
+            <artifactId>hutool-all</artifactId>
+            <version>5.8.37</version>
+        </dependency>
     </dependencies>
 
     <build>
diff --git a/aps-gateway/src/main/java/com/aps/gateway/config/loadBalancer/GrayLoadBalancer.java b/aps-gateway/src/main/java/com/aps/gateway/config/loadBalancer/GrayLoadBalancer.java
new file mode 100644
index 0000000..1bf7457
--- /dev/null
+++ b/aps-gateway/src/main/java/com/aps/gateway/config/loadBalancer/GrayLoadBalancer.java
@@ -0,0 +1,10 @@
+package com.aps.gateway.config.loadBalancer;
+
+import org.springframework.cloud.client.ServiceInstance;
+import org.springframework.http.server.reactive.ServerHttpRequest;
+
+
+public interface GrayLoadBalancer {
+
+    ServiceInstance choose(String serviceId, ServerHttpRequest request);
+}
diff --git a/aps-gateway/src/main/java/com/aps/gateway/config/loadBalancer/GrayReactiveLoadBalancerClientFilter.java b/aps-gateway/src/main/java/com/aps/gateway/config/loadBalancer/GrayReactiveLoadBalancerClientFilter.java
new file mode 100644
index 0000000..fb73979
--- /dev/null
+++ b/aps-gateway/src/main/java/com/aps/gateway/config/loadBalancer/GrayReactiveLoadBalancerClientFilter.java
@@ -0,0 +1,99 @@
+package com.aps.gateway.config.loadBalancer;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.http.util.Asserts;
+import org.springframework.cloud.client.ServiceInstance;
+import org.springframework.cloud.client.loadbalancer.DefaultResponse;
+import org.springframework.cloud.client.loadbalancer.LoadBalancerUriTools;
+import org.springframework.cloud.client.loadbalancer.Response;
+import org.springframework.cloud.gateway.config.GatewayLoadBalancerProperties;
+import org.springframework.cloud.gateway.filter.GatewayFilterChain;
+import org.springframework.cloud.gateway.filter.ReactiveLoadBalancerClientFilter;
+import org.springframework.cloud.gateway.support.DelegatingServiceInstance;
+import org.springframework.cloud.gateway.support.NotFoundException;
+import org.springframework.cloud.gateway.support.ServerWebExchangeUtils;
+import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
+import org.springframework.stereotype.Component;
+import org.springframework.web.server.ServerWebExchange;
+import reactor.core.publisher.Mono;
+
+import java.net.URI;
+
+
+@Slf4j
+@Component
+public class GrayReactiveLoadBalancerClientFilter extends ReactiveLoadBalancerClientFilter  {
+
+    private final static String SCHEME = "lb";
+
+    private static final int LOAD_BALANCER_CLIENT_FILTER_ORDER = 10150;
+    private final GrayLoadBalancer grayLoadBalancer;
+    private final GatewayLoadBalancerProperties loadBalancerProperties;
+
+    public GrayReactiveLoadBalancerClientFilter(LoadBalancerClientFactory clientFactory, GatewayLoadBalancerProperties loadBalancerProperties, GrayLoadBalancer grayLoadBalancer) {
+        super(clientFactory, loadBalancerProperties);
+        this.loadBalancerProperties = loadBalancerProperties;
+        this.grayLoadBalancer = grayLoadBalancer;
+    }
+
+    @Override
+    public int getOrder() {
+        return LOAD_BALANCER_CLIENT_FILTER_ORDER;
+    }
+
+    @Override
+    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
+        URI url = exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR);
+        String schemePrefix = exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_SCHEME_PREFIX_ATTR);
+
+        // 鐩存帴鏀捐
+        if (url == null || (!SCHEME.equals(url.getScheme()) && !SCHEME.equals(schemePrefix))) {
+            return chain.filter(exchange);
+        }
+        // 淇濈暀鍘熷url
+        ServerWebExchangeUtils.addOriginalRequestUrl(exchange, url);
+
+        if (log.isTraceEnabled()) {
+            log.trace(ReactiveLoadBalancerClientFilter.class.getSimpleName() + " url before: " + url);
+        }
+
+        return choose(exchange).doOnNext(response -> {
+
+            if (!response.hasServer()) {
+                throw NotFoundException.create(loadBalancerProperties.isUse404(),
+                        "Unable to find instance for " + url.getHost());
+            }
+
+            URI uri = exchange.getRequest().getURI();
+
+            // if the `lb:<scheme>` mechanism was used, use `<scheme>` as the default,
+            // if the loadbalancer doesn't provide one.
+            String overrideScheme = null;
+            if (schemePrefix != null) {
+                overrideScheme = url.getScheme();
+            }
+
+            DelegatingServiceInstance serviceInstance = new DelegatingServiceInstance(response.getServer(),
+                    overrideScheme);
+
+            URI requestUrl = LoadBalancerUriTools.reconstructURI(serviceInstance, uri);
+
+            if (log.isTraceEnabled()) {
+                log.trace("LoadBalancerClientFilter url chosen: " + requestUrl);
+            }
+            exchange.getAttributes().put(ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR, requestUrl);
+        }).then(chain.filter(exchange));
+    }
+
+    /**
+     * 鑾峰彇瀹炰緥
+     * @param exchange ServerWebExchange
+     * @return ServiceInstance
+     */
+    private Mono<Response<ServiceInstance>> choose(ServerWebExchange exchange) {
+        URI uri = exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR);
+        Asserts.notNull(uri, "uri");
+        ServiceInstance serviceInstance = grayLoadBalancer.choose(uri.getHost(), exchange.getRequest());
+        return Mono.just(new DefaultResponse(serviceInstance));
+    }
+}
\ No newline at end of file
diff --git a/aps-gateway/src/main/java/com/aps/gateway/config/loadBalancer/VersionGrayLoadBalancer.java b/aps-gateway/src/main/java/com/aps/gateway/config/loadBalancer/VersionGrayLoadBalancer.java
new file mode 100644
index 0000000..8946d45
--- /dev/null
+++ b/aps-gateway/src/main/java/com/aps/gateway/config/loadBalancer/VersionGrayLoadBalancer.java
@@ -0,0 +1,60 @@
+package com.aps.gateway.config.loadBalancer;
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.map.MapUtil;
+import cn.hutool.core.util.RandomUtil;
+import cn.hutool.core.util.StrUtil;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.logging.log4j.util.Strings;
+import org.springframework.cloud.client.ServiceInstance;
+import org.springframework.cloud.client.discovery.DiscoveryClient;
+import org.springframework.cloud.gateway.support.NotFoundException;
+import org.springframework.http.server.reactive.ServerHttpRequest;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+@Slf4j
+@RequiredArgsConstructor
+@Component
+public class VersionGrayLoadBalancer implements GrayLoadBalancer {
+
+    private final DiscoveryClient discoveryClient;
+    private final static String VERSION = "version";
+    /**
+     * 鏍规嵁serviceId 绛涢�夊彲鐢ㄦ湇鍔�
+     * @param serviceId 鏈嶅姟ID
+     * @param request 褰撳墠璇锋眰
+     * @return ServiceInstance
+     */
+    @Override
+    public ServiceInstance choose(String serviceId, ServerHttpRequest request) {
+        List<ServiceInstance> instances = discoveryClient.getInstances(serviceId);
+
+        // 娉ㄥ唽涓績鏃犲疄渚� 鎶涘嚭寮傚父
+        if (instances.isEmpty()) {
+            log.warn("No instance available for {}", serviceId);
+            throw new NotFoundException("No instance available for " + serviceId);
+        }
+
+        // 鑾峰彇璇锋眰version锛屾棤鍒欓殢鏈鸿繑鍥炲彲鐢ㄥ疄渚�
+        String reqVersion = request.getHeaders().getFirst(VERSION);
+        if (Strings.isBlank(reqVersion)) {
+            return instances.get(RandomUtil.randomInt(instances.size()));
+        }
+
+        // 閬嶅巻鍙互瀹炰緥鍏冩暟鎹紝鑻ュ尮閰嶅垯杩斿洖姝ゅ疄渚�
+        List<ServiceInstance> availableList = instances.stream()
+                .filter(instance -> reqVersion
+                        .equalsIgnoreCase(MapUtil.getStr(instance.getMetadata(), VERSION)))
+                .collect(Collectors.toList());
+
+        if (CollUtil.isEmpty(availableList)) {
+            return instances.get(RandomUtil.randomInt(instances.size()));
+        }
+        return availableList.get(RandomUtil.randomInt(availableList.size()));
+
+    }
+}
+

--
Gitblit v1.9.3