You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@shenyu.apache.org by li...@apache.org on 2023/05/05 11:51:19 UTC

[shenyu] branch master updated: refactor webfilter (#4614)

This is an automated email from the ASF dual-hosted git repository.

likeguo pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shenyu.git


The following commit(s) were added to refs/heads/master by this push:
     new cf506eb08 refactor webfilter (#4614)
cf506eb08 is described below

commit cf506eb081c1cbf2435824f36b8842f1e148f063
Author: xiaoyu <xi...@apache.org>
AuthorDate: Fri May 5 19:51:13 2023 +0800

    refactor webfilter (#4614)
    
    Co-authored-by: xiaoyu137 <xi...@jd.com>
---
 .../config/CollapseSlashesConfiguration.java       | 59 ----------------------
 .../src/main/resources/application.yml             |  5 +-
 .../starter/gateway/ShenyuConfiguration.java       | 34 +++++++++----
 .../shenyu/web/filter/CollapseSlashesFilter.java   | 44 ++++++++++++++++
 .../org/apache/shenyu/web/filter/HealthFilter.java | 19 ++++---
 .../apache/shenyu/web/filter/HealthFilterTest.java | 40 +++++++--------
 6 files changed, 97 insertions(+), 104 deletions(-)

diff --git a/shenyu-bootstrap/src/main/java/org/apache/shenyu/bootstrap/config/CollapseSlashesConfiguration.java b/shenyu-bootstrap/src/main/java/org/apache/shenyu/bootstrap/config/CollapseSlashesConfiguration.java
deleted file mode 100644
index 72607b2b8..000000000
--- a/shenyu-bootstrap/src/main/java/org/apache/shenyu/bootstrap/config/CollapseSlashesConfiguration.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.shenyu.bootstrap.config;
-
-import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.http.server.reactive.ServerHttpRequest;
-import org.springframework.web.server.ServerWebExchange;
-import org.springframework.web.server.WebFilter;
-import org.springframework.web.server.WebFilterChain;
-
-import java.net.URI;
-
-/**
- * Tolerant Path Slash.
- */
-@Configuration
-public class CollapseSlashesConfiguration {
-
-    /**
-     * declaration collapseSlashesFilter.
-     * @return collapseSlashesFilter
-     */
-    @Bean
-    @ConditionalOnProperty(
-            value = "shenyu.switchConfig.collapseSlashes",
-            havingValue = "true"
-    )
-    public WebFilter collapseSlashesFilter() {
-        return (ServerWebExchange exchange, WebFilterChain chain) -> {
-            ServerHttpRequest request = exchange.getRequest();
-            String newPath = request.getURI().getRawPath().replaceAll("/{2,}", "/");
-            if (!request.getURI().getRawPath().equals(newPath)) {
-                URI newUri = request.getURI().resolve(newPath);
-                ServerHttpRequest newRequest = request.mutate().uri(newUri).build();
-                return chain.filter(exchange.mutate().request(newRequest).build());
-            }
-            return chain.filter(exchange);
-        };
-    }
-}
-
-
diff --git a/shenyu-bootstrap/src/main/resources/application.yml b/shenyu-bootstrap/src/main/resources/application.yml
index 5646682ec..87e400a51 100644
--- a/shenyu-bootstrap/src/main/resources/application.yml
+++ b/shenyu-bootstrap/src/main/resources/application.yml
@@ -234,12 +234,11 @@ shenyu:
     paths:
       - /fallback/hystrix
       - /fallback/resilience4j
+      - /fallback/sentinel
   health:
     enabled: false
     paths:
-      - /actuator/health
-      - /actuator/health/readiness
-      - /actuator/health/liveness
+      - /actuator
       - /health_check
   extPlugin:
     path:
diff --git a/shenyu-spring-boot-starter/shenyu-spring-boot-starter-gateway/src/main/java/org/apache/shenyu/springboot/starter/gateway/ShenyuConfiguration.java b/shenyu-spring-boot-starter/shenyu-spring-boot-starter-gateway/src/main/java/org/apache/shenyu/springboot/starter/gateway/ShenyuConfiguration.java
index 89bd4920e..070c0cb69 100644
--- a/shenyu-spring-boot-starter/shenyu-spring-boot-starter-gateway/src/main/java/org/apache/shenyu/springboot/starter/gateway/ShenyuConfiguration.java
+++ b/shenyu-spring-boot-starter/shenyu-spring-boot-starter-gateway/src/main/java/org/apache/shenyu/springboot/starter/gateway/ShenyuConfiguration.java
@@ -32,6 +32,7 @@ import org.apache.shenyu.sync.data.api.PluginDataSubscriber;
 import org.apache.shenyu.web.configuration.ErrorHandlerConfiguration;
 import org.apache.shenyu.web.configuration.ShenyuExtConfiguration;
 import org.apache.shenyu.web.configuration.SpringExtConfiguration;
+import org.apache.shenyu.web.filter.CollapseSlashesFilter;
 import org.apache.shenyu.web.filter.CrossFilter;
 import org.apache.shenyu.web.filter.ExcludeFilter;
 import org.apache.shenyu.web.filter.FallbackFilter;
@@ -78,12 +79,12 @@ public class ShenyuConfiguration {
      * logger.
      */
     private static final Logger LOG = LoggerFactory.getLogger(ShenyuConfiguration.class);
-
+    
     /**
      * Init ShenyuWebHandler.
      *
-     * @param plugins             this plugins is All impl ShenyuPlugin.
-     * @param config              the config
+     * @param plugins this plugins is All impl ShenyuPlugin.
+     * @param config the config
      * @param shenyuLoaderService theLoaderServer
      * @return {@linkplain ShenyuWebHandler}
      */
@@ -131,7 +132,7 @@ public class ShenyuConfiguration {
         return new CommonPluginDataSubscriber(pluginDataHandlerList.getIfAvailable(Collections::emptyList),
                 eventPublisher.getIfAvailable(), shenyuConfig.getTrie());
     }
-
+    
     /**
      * common meta data subscriber.
      *
@@ -169,6 +170,18 @@ public class ShenyuConfiguration {
         return new ForwardedRemoteAddressResolver(1);
     }
     
+    /**
+     * Collapse slashes filter web filter.
+     *
+     * @return the web filter
+     */
+    @Bean
+    @Order(-300)
+    @ConditionalOnProperty(value = "shenyu.switchConfig.collapseSlashes", havingValue = "true")
+    public WebFilter collapseSlashesFilter() {
+        return new CollapseSlashesFilter();
+    }
+    
     /**
      * Local dispatcher filter.
      *
@@ -243,14 +256,15 @@ public class ShenyuConfiguration {
     /**
      * Health filter.
      *
+     * @param dispatcherHandler the dispatcher handler
      * @param shenyuConfig the shenyu config
      * @return the web filter
      */
     @Bean
     @Order(-99)
     @ConditionalOnProperty(name = "shenyu.health.enabled", havingValue = "true")
-    public WebFilter healthFilter(final ShenyuConfig shenyuConfig) {
-        return new HealthFilter(shenyuConfig.getHealth().getPaths());
+    public WebFilter healthFilter(final DispatcherHandler dispatcherHandler, final ShenyuConfig shenyuConfig) {
+        return new HealthFilter(dispatcherHandler, shenyuConfig.getHealth().getPaths());
     }
     
     /**
@@ -263,23 +277,23 @@ public class ShenyuConfiguration {
     public ShenyuConfig shenyuConfig() {
         return new ShenyuConfig();
     }
-
+    
     /**
      * shenyu trie config.
      *
      * @param shenyuConfig shenyu trie config
-     * @return ShenyuTrie
+     * @return ShenyuTrie shenyu trie
      */
     @Bean
     public ShenyuTrie shenyuTrie(final ShenyuConfig shenyuConfig) {
         return new ShenyuTrie(shenyuConfig.getTrie().getChildrenSize(), shenyuConfig.getTrie().getPathRuleCacheSize(),
                 shenyuConfig.getTrie().getPathVariableSize(), shenyuConfig.getTrie().getMatchMode());
     }
-
+    
     /**
      * shenyu trie listener.
      *
-     * @return ShenyuTrieRuleListener
+     * @return ShenyuTrieRuleListener shenyu trie rule listener
      */
     @Bean
     public ShenyuTrieRuleListener shenyuTrieRuleListener() {
diff --git a/shenyu-web/src/main/java/org/apache/shenyu/web/filter/CollapseSlashesFilter.java b/shenyu-web/src/main/java/org/apache/shenyu/web/filter/CollapseSlashesFilter.java
new file mode 100644
index 000000000..a8c4c1b84
--- /dev/null
+++ b/shenyu-web/src/main/java/org/apache/shenyu/web/filter/CollapseSlashesFilter.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shenyu.web.filter;
+
+import org.springframework.http.server.reactive.ServerHttpRequest;
+import org.springframework.web.server.ServerWebExchange;
+import org.springframework.web.server.WebFilter;
+import org.springframework.web.server.WebFilterChain;
+import reactor.core.publisher.Mono;
+
+import java.net.URI;
+
+/**
+ * The type Collapse slashes filter.
+ */
+public class CollapseSlashesFilter implements WebFilter {
+    
+    @Override
+    public Mono<Void> filter(final ServerWebExchange exchange, final WebFilterChain chain) {
+        ServerHttpRequest request = exchange.getRequest();
+        String newPath = request.getURI().getRawPath().replaceAll("/{2,}", "/");
+        if (!request.getURI().getRawPath().equals(newPath)) {
+            URI newUri = request.getURI().resolve(newPath);
+            ServerHttpRequest newRequest = request.mutate().uri(newUri).build();
+            return chain.filter(exchange.mutate().request(newRequest).build());
+        }
+        return chain.filter(exchange);
+    }
+}
diff --git a/shenyu-web/src/main/java/org/apache/shenyu/web/filter/HealthFilter.java b/shenyu-web/src/main/java/org/apache/shenyu/web/filter/HealthFilter.java
index e2b5e62af..ac16327fc 100644
--- a/shenyu-web/src/main/java/org/apache/shenyu/web/filter/HealthFilter.java
+++ b/shenyu-web/src/main/java/org/apache/shenyu/web/filter/HealthFilter.java
@@ -18,14 +18,11 @@
 package org.apache.shenyu.web.filter;
 
 import org.apache.commons.collections4.CollectionUtils;
-import org.apache.shenyu.common.utils.JsonUtils;
-import org.springframework.boot.actuate.health.Health;
-import org.springframework.core.io.buffer.DataBuffer;
+import org.springframework.web.reactive.DispatcherHandler;
 import org.springframework.web.server.ServerWebExchange;
 import org.springframework.web.server.WebFilterChain;
 import reactor.core.publisher.Mono;
 
-import java.nio.charset.StandardCharsets;
 import java.util.Arrays;
 import java.util.HashSet;
 import java.util.List;
@@ -36,16 +33,20 @@ import java.util.Set;
  */
 public final class HealthFilter extends AbstractWebFilter {
     
+    private final DispatcherHandler dispatcherHandler;
+    
     private final Set<String> paths;
     
     /**
      * Instantiates a new Health filter.
      *
+     * @param dispatcherHandler the dispatcher handler
      * @param paths the paths
      */
-    public HealthFilter(final List<String> paths) {
+    public HealthFilter(final DispatcherHandler dispatcherHandler, final List<String> paths) {
+        this.dispatcherHandler = dispatcherHandler;
         if (CollectionUtils.isEmpty(paths)) {
-            this.paths = new HashSet<>(Arrays.asList("/actuator/health", "/actuator/health/readiness", "/actuator/health/liveness", "/health_check"));
+            this.paths = new HashSet<>(Arrays.asList("/actuator", "/health_check"));
         } else {
             this.paths = new HashSet<>(paths); 
         }
@@ -53,13 +54,11 @@ public final class HealthFilter extends AbstractWebFilter {
     
     @Override
     protected Mono<Boolean> doMatcher(final ServerWebExchange exchange, final WebFilterChain chain) {
-        return Mono.just(paths.contains(exchange.getRequest().getURI().getPath()));
+        return Mono.just(paths.stream().anyMatch(path -> exchange.getRequest().getURI().getPath().startsWith(path)));
     }
     
     @Override
     protected Mono<Void> doFilter(final ServerWebExchange exchange) {
-        String result = JsonUtils.toJson(new Health.Builder().up().build());
-        DataBuffer dataBuffer = exchange.getResponse().bufferFactory().wrap(result.getBytes(StandardCharsets.UTF_8));
-        return exchange.getResponse().writeWith(Mono.just(dataBuffer));
+        return dispatcherHandler.handle(exchange);
     }
 }
diff --git a/shenyu-web/src/test/java/org/apache/shenyu/web/filter/HealthFilterTest.java b/shenyu-web/src/test/java/org/apache/shenyu/web/filter/HealthFilterTest.java
index d5fc156e2..376ee367a 100644
--- a/shenyu-web/src/test/java/org/apache/shenyu/web/filter/HealthFilterTest.java
+++ b/shenyu-web/src/test/java/org/apache/shenyu/web/filter/HealthFilterTest.java
@@ -25,6 +25,7 @@ import org.mockito.junit.jupiter.MockitoSettings;
 import org.mockito.quality.Strictness;
 import org.springframework.mock.http.server.reactive.MockServerHttpRequest;
 import org.springframework.mock.web.server.MockServerWebExchange;
+import org.springframework.web.reactive.DispatcherHandler;
 import org.springframework.web.server.ServerWebExchange;
 import org.springframework.web.server.WebFilterChain;
 import reactor.core.publisher.Mono;
@@ -51,25 +52,29 @@ public final class HealthFilterTest {
     @BeforeEach
     public void setUp() {
         List<String> paths = new ArrayList<>();
-        paths.add("/testFilterMatch");
-        healthFilter = new HealthFilter(paths);
+        paths.add("/health_check");
+        paths.add("/actuator");
+        DispatcherHandler dispatcherHandler = mock(DispatcherHandler.class);
+        when(dispatcherHandler.handle(any())).thenReturn(Mono.empty());
+        healthFilter = new HealthFilter(dispatcherHandler, paths);
         webFilterChain = mock(WebFilterChain.class);
         when(webFilterChain.filter(any())).thenReturn(Mono.empty());
     }
 
     @Test
     public void testDoMatcher() {
-        ServerWebExchange webExchange =
-                MockServerWebExchange.from(MockServerHttpRequest
-                        .post("http://localhost:8080/testFilterMatch"));
-        Mono<Boolean> filter = healthFilter.doMatcher(webExchange, webFilterChain);
-        StepVerifier.create(filter).expectNext(Boolean.TRUE).verifyComplete();
-    }
-
-    @Test
-    public void testPathNull() {
-        List<String> paths = new ArrayList<>();
-        new HealthFilter(paths);
+        Mono<Boolean> health = healthFilter.doMatcher(MockServerWebExchange
+                .from(MockServerHttpRequest.post("http://localhost:8080/actuator/health")), webFilterChain);
+        StepVerifier.create(health).expectNext(Boolean.TRUE).verifyComplete();
+    
+        Mono<Boolean> healthCheck = healthFilter.doMatcher(MockServerWebExchange
+                .from(MockServerHttpRequest.post("http://localhost:8080/health_check")), webFilterChain);
+        StepVerifier.create(healthCheck).expectNext(Boolean.TRUE).verifyComplete();
+    
+        Mono<Boolean> readiness = healthFilter.doMatcher(MockServerWebExchange
+                .from(MockServerHttpRequest.post("http://localhost:8080/actuator/health/readiness")), webFilterChain);
+        StepVerifier.create(readiness).expectNext(Boolean.TRUE).verifyComplete();
+        
     }
 
     @Test
@@ -81,13 +86,4 @@ public final class HealthFilterTest {
         StepVerifier.create(filter).expectNext(Boolean.FALSE).verifyComplete();
     }
 
-    @Test
-    public void testDoFilter() {
-        ServerWebExchange webExchange =
-                MockServerWebExchange.from(MockServerHttpRequest
-                        .post("http://localhost:8080/"));
-        Mono<Void> filter = healthFilter.doFilter(webExchange);
-        StepVerifier.create(filter).verifyComplete();
-    }
-
 }