Spring Cloud Gateway中多规则限流(RequestRateLimiter覆盖问题)

场景

在SCG中配置多个RequestRateLimiter时,只能支持一个速率。

源码分析

跟踪源码发现下列两个关键类。

AbstractRateLimiter:初始化rarelimiter配置。

RequestRateLimiterGatewayFilterFactory:限流过滤器,包括定时刷新过滤器内容,和请求触发执行限流判断。

package org.springframework.cloud.gateway.filter.ratelimit;

...

public abstract class AbstractRateLimiter extends AbstractStatefulConfigurable
		implements RateLimiter, ApplicationListener {

	...
	@Override
	public void onApplicationEvent(FilterArgsEvent event) {
		Map args = event.getArgs();

		if (args.isEmpty() || !hasRelevantKey(args)) {
			return;
		}
        //获取路由id,包括默认的defaultFilters
		String routeId = event.getRouteId();
        //使用routeId+KeyResolver.hashcode作为配置id,防止重复
        routeId = routeId + event.getArgs().get("key-resolver").hashCode();
		C routeConfig = newConfig();
		if (this.configurationService != null) {
			this.configurationService.with(routeConfig)
					.name(this.configurationPropertyName).normalizedProperties(args)
					.bind();
		}
        //更新速率配置集合,routeId一致会覆盖
		getConfig().put(routeId, routeConfig);
	}

	...
}

 


package org.springframework.cloud.gateway.filter.factory;

...
/**
 * User Request Rate Limiter filter. See https://stripe.com/blog/rate-limiters and
 * https://gist.github.com/ptarjan/e38f45f2dfe601419ca3af937fff574d#file-1-check_request_rate_limiter-rb-L11-L34.
 */
@ConfigurationProperties("spring.cloud.gateway.filter.request-rate-limiter")
public class RequestRateLimiterGatewayFilterFactory extends
		AbstractGatewayFilterFactory {

	...

	@SuppressWarnings("unchecked")
	@Override
	public GatewayFilter apply(Config config) {
		KeyResolver resolver = getOrDefault(config.keyResolver, defaultKeyResolver);
		RateLimiter limiter = getOrDefault(config.rateLimiter,
				defaultRateLimiter);
		boolean denyEmpty = getOrDefault(config.denyEmptyKey, this.denyEmptyKey);
		HttpStatusHolder emptyKeyStatus = HttpStatusHolder
				.parse(getOrDefault(config.emptyKeyStatus, this.emptyKeyStatusCode));

		return (exchange, chain) -> resolver.resolve(exchange).defaultIfEmpty(EMPTY_KEY)
				.flatMap(key -> {
					if (EMPTY_KEY.equals(key)) {
						if (denyEmpty) {
							setResponseStatus(exchange, emptyKeyStatus);
							return exchange.getResponse().setComplete();
						}
						return chain.filter(exchange);
					}
                    //获取routeid
					String routeId = config.getRouteId();
                    //使用routeId+KeyResolver.hashcode获取config
					routeId = routeId + config.getKeyResolver().hashCode();
					if (routeId == null) {
						Route route = exchange
								.getAttribute(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR);
						routeId = route.getId();
					}
                    //根据routeid获取limiter中配置
					return limiter.isAllowed(routeId, key).flatMap(response -> {

						for (Map.Entry header : response.getHeaders()
								.entrySet()) {
							exchange.getResponse().getHeaders().add(header.getKey(),
									header.getValue());
						}

						if (response.isAllowed()) {
							return chain.filter(exchange);
						}

						setResponseStatus(exchange, config.getStatusCode());
						return exchange.getResponse().setComplete();
					});
				});
	}

}

 

 

修改方案

新建上述两个文件,使用本地代码覆盖jar包源码,包名一致则可优先使用本地。

Spring Cloud Gateway中多规则限流(RequestRateLimiter覆盖问题)_第1张图片

效果如下:

Spring Cloud Gateway中多规则限流(RequestRateLimiter覆盖问题)_第2张图片

你可能感兴趣的:(SpringCloud,网关,Gateway,SCG,ratelimit,多限流)