{"id":37027616,"url":"https://github.com/chenggangpro/spring-cloud-gateway-plugin","last_synced_at":"2026-01-14T03:17:15.630Z","repository":{"id":34587762,"uuid":"168107775","full_name":"chenggangpro/spring-cloud-gateway-plugin","owner":"chenggangpro","description":"Spring Cloud Gateway Extra Plugin","archived":false,"fork":false,"pushed_at":"2022-06-17T02:59:10.000Z","size":143,"stargazers_count":176,"open_issues_count":1,"forks_count":67,"subscribers_count":7,"default_branch":"2.1.SR1.x","last_synced_at":"2025-07-26T04:25:21.550Z","etag":null,"topics":["spring-cloud","springcloudgateway","springcloudgreenwich"],"latest_commit_sha":null,"homepage":null,"language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/chenggangpro.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-01-29T07:12:30.000Z","updated_at":"2025-05-16T01:32:11.000Z","dependencies_parsed_at":"2022-09-01T23:40:59.871Z","dependency_job_id":null,"html_url":"https://github.com/chenggangpro/spring-cloud-gateway-plugin","commit_stats":null,"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"purl":"pkg:github/chenggangpro/spring-cloud-gateway-plugin","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chenggangpro%2Fspring-cloud-gateway-plugin","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chenggangpro%2Fspring-cloud-gateway-plugin/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chenggangpro%2Fspring-cloud-gateway-plugin/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chenggangpro%2Fspring-cloud-gateway-plugin/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/chenggangpro","download_url":"https://codeload.github.com/chenggangpro/spring-cloud-gateway-plugin/tar.gz/refs/heads/2.1.SR1.x","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chenggangpro%2Fspring-cloud-gateway-plugin/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28408824,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-14T01:52:23.358Z","status":"online","status_checked_at":"2026-01-14T02:00:06.678Z","response_time":107,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["spring-cloud","springcloudgateway","springcloudgreenwich"],"created_at":"2026-01-14T03:17:14.988Z","updated_at":"2026-01-14T03:17:15.621Z","avatar_url":"https://github.com/chenggangpro.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# WARNING\n\u003e This Project Is Archives,Can't catch up the spring-cloud-version.But the code and the thought is much more useful for who want adapt spring-cloud-gateway to his own project \n# spring-cloud-gateway-plugin\nSpring Cloud Gateway Extra Plugin\n\n[![Build Status](https://travis-ci.com/chenggangpro/spring-cloud-gateway-plugin.svg?branch=master)](https://travis-ci.com/chenggangpro/spring-cloud-gateway-plugin)\n\n## Current Version\n\n\n|Gateway Version|Plugin Version|\n|:--|:--|\n|`Greenwich.SR1`|`2.1.SR1.3.RELEASE`|\n|`Greenwich.SR2`|`2.1.SR2.2.RELEASE`|\n\n\n\u003e More Detail See [Wiki](https://github.com/chenggangpro/spring-cloud-gateway-plugin/wiki)\n\n### This Plugin Support Below Features:\n\n* [x] Cache Request Body And Form Body\n* [x] Add Request Log Filter To Log Request And Response\n* [x] Add Read Json Response Body And Log Response Body\n* [x] Add Global Exception Handler With Json\n* [x] Add Custom Exception Handler\n* [x] Add Grey Route With Ribbon And Eureka\n* [x] Each Route Use different Hystrix CommandKey \n* [x] Support Dynamic Predicate With Existing Routes\n\n### How To Use This Feature\n\n##### Note:\n \n   * This Dependency Base Spring Cloud Gateway[`Greenwich.SR1`],Suggest To Update To This SpringCloud Version,Official Resolve Some Issues , Fix Some Bugs.\n   * The SpringBoot Version need to update to [`2.1.6.RELEASE`],It fix reactor-netty issues\n   * This Dependency Is Now In Maven Central. \n   * The Feature To Read Request And Response Json Data Will Loss A Lot Of Performance,It Will Reduce The Gateway Traffic.\n\n##### Step\n\n* 1 . Include Dependency\n    \n    \u003e Spring Cloud Gateway\n    \n    ```xml\n    \u003cdependencies\u003e\n        \u003cdependency\u003e\n            \u003cgroupId\u003eorg.springframework.cloud\u003c/groupId\u003e\n            \u003cartifactId\u003espring-cloud-starter-gateway\u003c/artifactId\u003e\n        \u003c/dependency\u003e\n        \u003c!--If you need to use grey route,you should add next dependency ,but grey route only can be used with eureka discover--\u003e\n        \u003cdependency\u003e\n            \u003cgroupId\u003eorg.springframework.cloud\u003c/groupId\u003e\n            \u003cartifactId\u003espring-cloud-starter-netflix-eureka-client\u003c/artifactId\u003e\n        \u003c/dependency\u003e\n    \u003c/dependencies\u003e\n\n    \u003cdependencyManagement\u003e\n        \u003cdependencies\u003e\n            \u003cdependency\u003e\n                \u003cgroupId\u003eorg.springframework.cloud\u003c/groupId\u003e\n                \u003cartifactId\u003espring-cloud-dependencies\u003c/artifactId\u003e\n                \u003cversion\u003eGreenwich.SR1\u003c/version\u003e\n                \u003ctype\u003epom\u003c/type\u003e\n                \u003cscope\u003eimport\u003c/scope\u003e\n            \u003c/dependency\u003e\n        \u003c/dependencies\u003e\n    \u003c/dependencyManagement\u003e\n    ```\n    \u003e Gateway Plugin\n    \n    ```xml\n    \u003cdependency\u003e\n        \u003cgroupId\u003epro.chenggang\u003c/groupId\u003e\n        \u003cartifactId\u003espring-cloud-gateway-plugin\u003c/artifactId\u003e\n        \u003cversion\u003e2.1.SR1.1.RELEASE\u003c/version\u003e\n    \u003c/dependency\u003e\n    ```\n  \n* 2 . Add Enable Annotation To You Application\n\n    ```java\n    @EnableGatewayPlugin\n    public class SpringCloudGatewayPluginApplication {\n    \n        public static void main(String[] args) {\n            SpringApplication.run(SpringCloudGatewayPluginApplication.class, args);\n        }\n    \n    }\n    ```\n\n    Note: If You User SpringBoot 2.1.0+,You should set `allow-bean-definition-overriding` to `true`\n\n    ```yaml\n    spring:\n      main:\n        allow-bean-definition-overriding: true\n    ```\n\n* 3 . Choose Plugin Feature To Use\n\n    By use this annotation `@EnableGatewayPlugin` to enable the plugin,the plugin support switch to choose feature\n    By default,the `GatewayContext Filter` is always into system\n    \n    ```yaml\n    spring:\n      profiles:\n        active: dev\n      cloud:\n        gateway:\n          plugin:\n            config:\n              log-request: true\n              read-request-data: true # this setting will read all request data\n              read-response-data: true\n              exception-json-handler: true\n              enable-dynamic-route: true\n            grey:\n              enable: false\n              grey-ribbon-rule: weight_response\n    ```\n* 4 . Specific Setting To Enable Read Request Data\n\n    ```yaml\n    spring:\n      cloud:\n        gateway:\n          plugin:\n            config:\n              read-request-data-service-id-list:  #set specific serviceId from discover to read request Data\n                - serviceId1\n                - serviceId2\n              read-request-data-path-list:        #set specific path to read request data\n                - /service/path1/*\n                - /service/path2/**\n                - /service/path3  \n    ```\n\n* 5 . User GatewayContext\n\n    You Can Use GatewayContext To Get Cache JsonBody Or Form Body,Just Use\n\n    ```java\n    GatewayContext gatewayContext = exchange.getAttribute(GatewayContext.CACHE_GATEWAY_CONTEXT);\n    ```\n* 6 . The Deference Between `GreyRibbonRule.DEFAULT` And `GreyRibbonRule.WeightResponse`\n\n    The Default GreyRibbonRule Just Use Round Rule As Base Ribbon Rule\n    The WeightResponse GreyRibbonRule Use WeightResponse Rule As Base Ribbon Rule\n\n* 7 . The Grey Route\n\n    * Setup Gateway Properties\n \n    ```yaml\n    spring:\n      cloud:\n        gateway:\n          plugin:\n              grey:\n                grey-rule-list:\n                  - service-id: privider1\n                    version: 2.0.0\n                    operation: OR\n                    rules:\n                      - key: key1\n                        value:\n                          - value1\n                          - value2\n                          - value3\n                      - key: key2\n                        value:\n                          - value4\n                          - value5\n                          - value6\n                  - service-id: provider2\n                    version: 2.0.0\n                    operation: AND\n                    rules:\n                      - key: keya\n                        value:\n                          - value1a\n                          - value2a\n                          - value3a\n                      - key: keyb\n                        value:\n                          - value4b\n                          - value5b\n                          - value6b\n        \n     ```\n    \n    * Set Up Service MetaInfo\n    \n        ```yaml\n        #proiver1\n        eureka:\n          instance:\n            metadata-map:\n              version: 2.0.0 \n        ```\n    \n    * The Properties Active Rule Principle\n    \n        When Request URL Route To Provider1,When The Request JsonBody Or Form Data Contain The Key -\u003e`Key1` And Match Any Of The Value-\u003e[`value1`,`value2`,`value3`]\n        The Route The Request To The Service Which Setup The MetaInfo With Specific Version Which Match The Gateway Grey Setup \n    \n\n* 8 . How To Custom GlobalException Handler With Json\n\n    In Order To Handle Other Exception,You Can Define Specific Bean Implements `ExceptionHandlerStrategy`\n    By default,plugin supply `DefaultExceptionHandlerStrategy` In Case Of None Strategy Exist \n\n    ```java\n    @Slf4j\n    public class DefaultExceptionHandlerStrategy implements ExceptionHandlerStrategy {\n    \n        @Override\n        public Class getHandleClass() {\n            return Throwable.class;\n        }\n    \n        @Override\n        public ExceptionHandlerResult handleException(Throwable throwable) {\n            ResponseResult\u003cString\u003e responseResult = new ResponseResult\u003c\u003e(SystemResponseInfo.GATEWAY_ERROR,throwable.getMessage());\n            ExceptionHandlerResult result = new ExceptionHandlerResult(HttpStatus.INTERNAL_SERVER_ERROR, JSON.toJSONString(responseResult));\n            log.debug(\"[DefaultExceptionHandlerStrategy]Handle Exception:{},Result:{}\",throwable.getMessage(),result);\n            log.error(\"[DefaultExceptionHandlerStrategy]Log Exception In Error Level,Exception Message:{}\",throwable.getMessage());\n            return result;\n        }\n    }\n    ```\n    \n    Or You Can Use `@ExceptionHandler` just like below,\n    \n    The`@ResponseStatus` is optional,if you don't add `@ResponseStatus`,the default HttpStatus is HttpStatus.BAD_GATEWAY \n    \n    ```java\n    @Component\n    public class DemoExceptionHandler {\n    \n        @ExceptionHandler({NotFoundException.class})\n        @ResponseStatus(HttpStatus.NOT_FOUND)\n        public Map handlerException(ServerWebExchange exchange,TimeoutException throwable){\n            LinkedHashSet\u003cURI\u003e originalRequestUris = exchange.getAttributeOrDefault(ServerWebExchangeUtils.GATEWAY_ORIGINAL_REQUEST_URL_ATTR,null);\n            Map map = Maps.newHashMapWithExpectedSize(2);\n            map.put(\"URI\",originalRequestUris);\n            map.put(\"ExceptionMessage\",throwable.getClass().getSimpleName());\n            return map;\n        }\n      \n        @ExceptionHandler({ClientException.class, TimeoutException.class})\n        @ResponseStatus(HttpStatus.BAD_GATEWAY)\n        public Map handlerException(ServerWebExchange exchange,TimeoutException throwable){\n              LinkedHashSet\u003cURI\u003e originalRequestUris = exchange.getAttributeOrDefault(ServerWebExchangeUtils.GATEWAY_ORIGINAL_REQUEST_URL_ATTR,null);\n              Map map = Maps.newHashMapWithExpectedSize(2);\n              map.put(\"URI\",originalRequestUris);\n              map.put(\"ExceptionMessage\",throwable.getClass().getSimpleName());\n              return map;\n        }\n    }\n    ```\n\n* 9 . How To Use Dynamic Predicate With Existing Routes\n\n    * Define A Component Implements `DynamicRouteProcessor`,this processor process serverWebExchange for dynamic route predicate\n    \n    \u003e the `DynamicRouteProcessor` definition\n    \n    ```java\n    /**\n     * Process ServerWebExchange for dynamic route predicate\n     * @author chenggang\n     * @date 2019/07/17\n     */\n    public interface DynamicRouteProcessor\u003cT\u003e {\n    \n        /**\n         * preprocess action\n         * @param exchange ServerWebExchange\n         * @return process Result ,if result is Optional.empty(),then dynamic predicate not working\n         */\n        Optional\u003cPreprocessResult\u003cT\u003e\u003e preprocess(ServerWebExchange exchange);\n    \n        /**\n         * process to unify config for predicate\n         * @param preprocessResult pre process result\n         * @param route current route\n         * @return\n         */\n        Optional\u003cDynamicRouteConfig\u003e processConfig(PreprocessResult\u003cT\u003e preprocessResult, Route route);\n    \n        /**\n         * target predicate bean 's class\n         * @return RoutePredicateFactory Class\n         */\n        Optional\u003cClass\u003c ? extends AbstractRoutePredicateFactory\u003e\u003e targetPredicateBeanClass();\n    }\n    ```\n    \n    \u003e custom dynamic route processor\n    \n    ```java\n    @Component\n    public class CustomDynamicRouteProcessor implements DynamicRouteProcessor {\n    \n        @Override\n        public Optional\u003cPreprocessResult\u003e preprocess(ServerWebExchange exchange) {\n            String route = exchange.getRequest().getHeaders().getFirst(\"route\");\n            if(StringUtils.isBlank(route)){\n                return Optional.of(PreprocessResult.builder().result(false).build());\n            }\n            return Optional.of(PreprocessResult.builder().result(true).resultData(route).build());\n        }\n    \n        @Override\n        public Optional\u003cDynamicRouteConfig\u003e processConfig(PreprocessResult preprocessResult, Route route) {\n            if(!preprocessResult.getResult()){\n                return Optional.empty();\n            }\n            Object resultData = preprocessResult.getResultData();\n            if(!(resultData instanceof String)){\n                return Optional.empty();\n            }\n            String data = (String) resultData;\n            DemoDynamicRoutePredicateFactory.Config config = DemoDynamicRoutePredicateFactory.Config.builder().header(data).route(route).build();\n            return Optional.of(config);\n        }\n    \n        @Override\n        public Optional\u003cClass\u003c? extends AbstractRoutePredicateFactory\u003e\u003e targetPredicateBeanClass() {\n            return Optional.of(DemoDynamicRoutePredicateFactory.class);\n        }\n    }\n\n    ```\n    \n    \u003e Define a `AbstractRoutePredicateFactory` ,the `Config` Class Must Implements `DynamicRouteConfig`\n    \n    ```java\n    @Slf4j\n    @Component\n    public class DemoDynamicRoutePredicateFactory extends AbstractRoutePredicateFactory\u003cDemoDynamicRoutePredicateFactory.Config\u003e {\n    \n        public DemoDynamicRoutePredicateFactory() {\n            super(Config.class);\n        }\n    \n        @Override\n        public Predicate\u003cServerWebExchange\u003e apply(Config config) {\n            return exchange -\u003e {\n                Route route = config.getRoute();\n                if(Objects.isNull(route.getUri())){\n                    log.debug(\"Route Uri Is NUll Return False,RouteID:{}\",route.getId());\n                    return false;\n                }\n                String routeUriHost = route.getUri().getHost();\n                String headerData = config.getHeader();\n                if(StringUtils.isBlank(routeUriHost) || StringUtils.isBlank(headerData)){\n                    log.debug(\"Route Uri Host Or HeaderData Is Blank Return False,RouteID:{}\",route.getId());\n                    return false;\n                }\n                if(routeUriHost.equalsIgnoreCase(headerData)){\n                    log.debug(\"Route Uri Host Matched Header Data Return True,RouteID:{}\",route.getId());\n                    route.getFilters();\n                    return true;\n                }\n                log.debug(\"Route Uri Not Matched Return False,RouteID:{}\",route.getId());\n                return false;\n            };\n        }\n    \n        @Getter\n        @Setter\n        @Builder\n        @ToString\n        @AllArgsConstructor\n        public static class Config implements DynamicRouteConfig {\n    \n            private Route route;\n            private String header;\n    \n        }\n    }\n    ```\n    \n    This Feature Support dynamic predicate with existing routes,Fox example: You can according the custom header to match the loadbalance route,\n    \n    * More logical detail to see `DynamicRoutePredicateHandlerMapping`\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchenggangpro%2Fspring-cloud-gateway-plugin","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fchenggangpro%2Fspring-cloud-gateway-plugin","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchenggangpro%2Fspring-cloud-gateway-plugin/lists"}