From 0105e57ac8bf198795689ef4d6bc592794ddb6e9 Mon Sep 17 00:00:00 2001 From: Spencer Gibb Date: Wed, 22 Mar 2017 21:19:47 -0600 Subject: [PATCH] Adds sample Throttle WebFilter --- spring-cloud-gateway-sample/pom.xml | 5 ++ .../sample/GatewaySampleApplication.java | 17 +++++- .../sample/ThrottleWebFilterFactory.java | 60 +++++++++++++++++++ 3 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 spring-cloud-gateway-sample/src/main/java/org/springframework/cloud/gateway/sample/ThrottleWebFilterFactory.java diff --git a/spring-cloud-gateway-sample/pom.xml b/spring-cloud-gateway-sample/pom.xml index 1e8d5217..45229626 100644 --- a/spring-cloud-gateway-sample/pom.xml +++ b/spring-cloud-gateway-sample/pom.xml @@ -34,6 +34,11 @@ org.springframework.cloud spring-cloud-starter-gateway + + org.isomorphism + token-bucket + 1.7 + org.springframework.boot spring-boot-starter-test diff --git a/spring-cloud-gateway-sample/src/main/java/org/springframework/cloud/gateway/sample/GatewaySampleApplication.java b/spring-cloud-gateway-sample/src/main/java/org/springframework/cloud/gateway/sample/GatewaySampleApplication.java index 9035199a..8232830f 100644 --- a/spring-cloud-gateway-sample/src/main/java/org/springframework/cloud/gateway/sample/GatewaySampleApplication.java +++ b/spring-cloud-gateway-sample/src/main/java/org/springframework/cloud/gateway/sample/GatewaySampleApplication.java @@ -28,6 +28,7 @@ import org.springframework.context.annotation.Bean; import static org.springframework.cloud.gateway.filter.factory.WebFilterFactories.addResponseHeader; import static org.springframework.cloud.gateway.handler.predicate.RoutePredicates.host; import static org.springframework.cloud.gateway.handler.predicate.RoutePredicates.path; +import static org.springframework.tuple.TupleBuilder.tuple; /** * @author Spencer Gibb @@ -38,7 +39,7 @@ import static org.springframework.cloud.gateway.handler.predicate.RoutePredicate public class GatewaySampleApplication { @Bean - public RouteLocator customRouteLocator() { + public RouteLocator customRouteLocator(ThrottleWebFilterFactory throttle) { return Routes.locator() .route("test") .uri("http://httpbin.org:80") @@ -50,9 +51,23 @@ public class GatewaySampleApplication { .predicate(path("/image/webp")) .add(addResponseHeader("X-AnotherHeader", "baz")) .and() + .route("test3") + .order(-1) + .uri("http://httpbin.org:80") + .predicate(host("**.throttle.org").and(path("/get"))) + .add(throttle.apply(tuple().of("capacity", 1, + "refillTokens", 1, + "refillPeriod", 10, + "refillUnit", "SECONDS"))) + .and() .build(); } + @Bean + public ThrottleWebFilterFactory throttleWebFilterFactory() { + return new ThrottleWebFilterFactory(); + } + public static void main(String[] args) { SpringApplication.run(GatewaySampleApplication.class, args); } diff --git a/spring-cloud-gateway-sample/src/main/java/org/springframework/cloud/gateway/sample/ThrottleWebFilterFactory.java b/spring-cloud-gateway-sample/src/main/java/org/springframework/cloud/gateway/sample/ThrottleWebFilterFactory.java new file mode 100644 index 00000000..dba50411 --- /dev/null +++ b/spring-cloud-gateway-sample/src/main/java/org/springframework/cloud/gateway/sample/ThrottleWebFilterFactory.java @@ -0,0 +1,60 @@ +/* + * Copyright 2013-2017 the original author or authors. + * + * Licensed 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.springframework.cloud.gateway.sample; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.isomorphism.util.TokenBucket; +import org.isomorphism.util.TokenBuckets; +import org.springframework.cloud.gateway.filter.factory.WebFilterFactory; +import org.springframework.http.HttpStatus; +import org.springframework.tuple.Tuple; +import org.springframework.web.server.WebFilter; + +import java.util.concurrent.TimeUnit; + +/** + * Sample throttling filter. + * See https://github.com/bbeck/token-bucket + */ +public class ThrottleWebFilterFactory implements WebFilterFactory { + private Log log = LogFactory.getLog(getClass()); + + @Override + public WebFilter apply(Tuple args) { + int capacity = args.getInt("capacity"); + int refillTokens = args.getInt("refillTokens"); + int refillPeriod = args.getInt("refillPeriod"); + TimeUnit refillUnit = TimeUnit.valueOf(args.getString("refillUnit")); + + final TokenBucket tokenBucket = TokenBuckets.builder() + .withCapacity(capacity) + .withFixedIntervalRefillStrategy(refillTokens, refillPeriod, refillUnit) + .build(); + + return (exchange, chain) -> { + log.debug("TokenBucket capacity: " + tokenBucket.getCapacity()); + boolean consumed = tokenBucket.tryConsume(); + if (consumed) { + return chain.filter(exchange); + } + exchange.getResponse().setStatusCode(HttpStatus.TOO_MANY_REQUESTS); + return exchange.getResponse().setComplete(); + }; + } +}