Open cui1100 opened 5 years ago
Hi, could you please give a code snippet to demonstrate your problem?
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.
I'll take a view these days.
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 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...
I'll take a view these days.
Big god , pay attention to my question please! We Need U
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.
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).
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
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