Gateway SentinelGatewayFilter throws FlowException after all the GlobalFilter excuted

sshcrbum  于 2022-04-21  发布在  Java
关注(0)|答案(9)|浏览(196)

My SpringCloud Gateway has lots of globla filters , the sentinel filter is first .
when the try number is larger than setting number, i hope that the sentinel throws the exception and finish,
but because of code chain.filter(exchange) ,all the filter would be excuted ,then throws my exception .

i want to ask that ,how to throw exception immediately if over the setting number , don't excute the other filters

bprjcwpo

bprjcwpo1#

Hi, could you please give a code snippet to demonstrate your problem?

mrzz3bfm

mrzz3bfm2#

First Filter:

@Component
public class FirstFilter implements GlobalFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        System.out.println("First Filter ------------");
        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        return 1;
    }
}

Copy of SentinelGatewayFilter:

@Override
    public int getOrder() {
        return 2;
    }

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        Route route = exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR);
        System.out.println("-------------Copy of SentinelGatewayFilter----------");
        Mono<Void> asyncResult = chain.filter(exchange);
        if (route != null) {
            String routeId = route.getId();
            Object[] params = paramParser.parseParameterFor(routeId, exchange,
                    r -> r.getResourceMode() == SentinelGatewayConstants.RESOURCE_MODE_ROUTE_ID);
            String origin = Optional.ofNullable(GatewayCallbackManager.getRequestOriginParser())
                    .map(f -> f.apply(exchange))
                    .orElse("");
            asyncResult = asyncResult.transform(
                    new SentinelReactorTransformer<>(new EntryConfig(routeId, EntryType.IN,
                            1, params, new ContextConfig(contextName(routeId), origin)))
            );
        }

        Set<String> matchingApis = pickMatchingApiDefinitions(exchange);
        for (String apiName : matchingApis) {
            Object[] params = paramParser.parseParameterFor(apiName, exchange,
                    r -> r.getResourceMode() == SentinelGatewayConstants.RESOURCE_MODE_CUSTOM_API_NAME);
            asyncResult = asyncResult.transform(
                    new SentinelReactorTransformer<>(new EntryConfig(apiName, EntryType.IN, 1, params))
            );
        }

        return asyncResult;
    }

Last Filter:

@Component
public class LastFilter implements GlobalFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        System.out.println("Last Filter ------------");
        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        return 3;
    }
}

I thought the demo would stop on the SentinelFilter(Order 2) and throws Exception, but the LastFilter(Order 3) printed and throwed exception then.

hsvhsicv

hsvhsicv3#

I'll take a view these days.

tgabmvqs

tgabmvqs4#

i think you need to adjust the filter's excution order,when the sentinel‘s filter is first execute Filter and throws exception, other’s filter has no time to execute。

c8ib6hqw

c8ib6hqw5#

i think you need to adjust the filter's excution order,when the sentinel‘s filter is first execute Filter and throws exception, other’s filter has no time to execute。

I Had try what u said, I deleted the first Filter, Sentinel Filter is first, but the last Filter still excuted and printed,then throws the FlowException...

rwqw0loc

rwqw0loc6#

I'll take a view these days.

Big god , pay attention to my question please! We Need U

ee7vknir

ee7vknir7#

May the problem locates on this line?

Mono<Void> asyncResult = chain.filter(exchange);

chain.filter at the beginning invoke the next filter first in future.

83qze16e

83qze16e8#

The filters in Spring Cloud Gateway is reactive (i.e. asynchronous), so chain.filter(exchange) does not actually invoke the next filter. The filters are invoked on subscription (i.e. when requests are coming).

The Sentinel Reactor operator wraps the subscribe operation with the Sentinel subscriber. For example:

public class MonoSentinelOperator<T> extends MonoOperator<T, T> {

    @Override
    public void subscribe(CoreSubscriber<? super T> actual) {
        source.subscribe(new SentinelReactorSubscriber<>(entryConfig, actual, true));
    }
}

This will trigger the onSubscribe event for downstream. The filter chain is wrapped with Mono.defer(), which will be triggered on subscription. See FilterWebHandler of Spring Cloud Gateway:

private static class DefaultGatewayFilterChain implements GatewayFilterChain {

		private final int index;

		private final List<GatewayFilter> filters;

		DefaultGatewayFilterChain(List<GatewayFilter> filters) {
			this.filters = filters;
			this.index = 0;
		}

		private DefaultGatewayFilterChain(DefaultGatewayFilterChain parent, int index) {
			this.filters = parent.getFilters();
			this.index = index;
		}

		public List<GatewayFilter> getFilters() {
			return filters;
		}

		@Override
		public Mono<Void> filter(ServerWebExchange exchange) {
			return Mono.defer(() -> {
				if (this.index < filters.size()) {
					GatewayFilter filter = filters.get(this.index);
					DefaultGatewayFilterChain chain = new DefaultGatewayFilterChain(this,
							this.index + 1);
					return filter.filter(exchange, chain);
				}
				else {
					return Mono.empty(); // complete
				}
			});
		}

	}

The asynchronous part of the proceeding filters won't be called actually (the Sentinel reactor subscriber will cut down the event if blocked). But this should be resolved, as some operations (not in the reactive stream) are indeed performed during subscription from upstream (this might be difficult to understand).

rsl1atfo

rsl1atfo9#

I also encountered the same problem. There are some custom filters in my gateway to process services, such as authorization authentication. When I put SentinelGatewayFilter first in the Filter chain, due to the line of Mono asyncResult = chain.filter(exchange), when ParamFlowException is thrown, SpringCloudGateway returns Mono.empty(), which is not expected of. The reason is because other business Filter has also been executed and committed Response. My expectation is that when the current limit occurs, it will not enter other filters. But now, I can only put SentinelGatewayFilter at the end. When other Filters are committed, I no longer enter SentinelGatewayFilter and return Response directly.

相关问题