source

In the construction principle of Route, Predicate, and Filter of SCG initial resolution, we mentioned that FilteringWebHandler is automatically assembled in the GatewayAutoConfiguration, without further elaboration.

@Bean
public FilteringWebHandler filteringWebHandler(List<GlobalFilter> globalFilters) {
	return new FilteringWebHandler(globalFilters);
}
Copy the code

You can see that all the GlobalFilters are combined during assembly.

public class FilteringWebHandler implements WebHandler {

	protected static final Log logger = LogFactory.getLog(FilteringWebHandler.class);

	private final List<GatewayFilter> globalFilters;

	public FilteringWebHandler(List<GlobalFilter> globalFilters) {
		this.globalFilters = loadFilters(globalFilters);
	}
	
    
	/** * This method mainly ADAPTS GlobalFilter to GatewayFilter *@param filters
	 * @return* /
	private static List<GatewayFilter> loadFilters(List<GlobalFilter> filters) {
		return filters.stream().map(filter -> {
			// Match GlobalFilter to GatewayFilter through GatewayFilterAdapter
			GatewayFilterAdapter gatewayFilter = new GatewayFilterAdapter(filter);
			// Determine whether GlobalFilter implements the Ordered interface
			if (filter instanceof Ordered) {
				int order = ((Ordered) filter).getOrder();
				//OrderedGatewayFilter is an OrderedGatewayFilter implementation class. In the FilterChain, the filter array is first ordered by order, filtering requests in order
				/ / return OrderedGatewayFilter
				return new OrderedGatewayFilter(gatewayFilter, order);
			}
			returngatewayFilter; }).collect(Collectors.toList()); }}Copy the code

GlobalFilter and GatewayFilter are explained below.

Last said to RoutePredicateHandlerMapping # to return FilteringWebHandler DispatcherHandler getHandlerInternal method.

class DispatcherHandler

@Override
public Mono<Void> handle(ServerWebExchange exchange) {
	if (this.handlerMappings == null) {
		return createNotFoundError();
	}
	return Flux.fromIterable(this.handlerMappings)
			.concatMap(mapping -> mapping.getHandler(exchange))
			.next()
        	//FilteringWebHandler
			.switchIfEmpty(createNotFoundError())
        	// Execute handler logic
			.flatMap(handler -> invokeHandler(exchange, handler))
			.flatMap(result -> handleResult(exchange, result));
}

private Mono<HandlerResult> invokeHandler(ServerWebExchange exchange, Object handler) {
	if (this.handlerAdapters ! =null) {
		
		for (HandlerAdapter handlerAdapter : this.handlerAdapters) {
			/ / $1
			if (handlerAdapter.supports(handler)) {
				returnhandlerAdapter.handle(exchange, handler); }}}return Mono.error(new IllegalStateException("No HandlerAdapter: " + handler));
}
Copy the code


At $1 it’s going to iterate over all of themHandlerAdapterDetermine whether this handler is supported and executehandleLogic.



It’s going to select thetaSimpleHandlerAdapter

SimpleHandlerAdapter

public class SimpleHandlerAdapter implements HandlerAdapter {

	@Override
	public boolean supports(Object handler) {
		return WebHandler.class.isAssignableFrom(handler.getClass());
	}

	@Override
	public Mono<HandlerResult> handle(ServerWebExchange exchange, Object handler) {
		WebHandler webHandler = (WebHandler) handler;
        / / call FilterWebHandler# handle
		Mono<Void> mono = webHandler.handle(exchange);
		returnmono.then(Mono.empty()); }}Copy the code

You can seeSimpleHandlerAdapterthesuppertsThe method is just judgmentWebHandlerWhether it ishandlerThe subclass.

FilteringWebHandler#handle

public class FilteringWebHandler implements WebHandler {
    
    private final List<GatewayFilter> globalFilters;
    
    @Override
	public Mono<Void> handle(ServerWebExchange exchange) {
        // The route is obtained
		Route route = exchange.getRequiredAttribute(GATEWAY_ROUTE_ATTR);
        // Obtain the Filter of the route
		List<GatewayFilter> gatewayFilters = route.getFilters();
		
		List<GatewayFilter> combined = new ArrayList<>(this.globalFilters);
		// Merge GlobalFilter and route Filter
        combined.addAll(gatewayFilters);
		// TODO: needed or cached?
		// Sort the Filter
		AnnotationAwareOrderComparator.sort(combined);

		if (logger.isDebugEnabled()) {
			logger.debug("Sorted gatewayFilterFactories: " + combined);
		}
		/ / create a FilterChain
		return newDefaultGatewayFilterChain(combined).filter(exchange); }}Copy the code

GatewayFilterChainThere is only one implementation in SCGDefaultGatewayFilterChain.FilterChainIt’s very simple and I’m not going to talk too much about it.



On the set of the figure





Now the request has reached the position of our red box in the figure aboveGatewayFilterChainThe proxy request is sent after the pre-filter is filtered, and the returned result is filtered through the post-filter and then returned.

Quotes from official documents

Clients make requests to Spring Cloud Gateway. If the Gateway Handler Mapping determines that a request matches a route, it is sent to the Gateway Web Handler. This handler runs the request through a filter chain that is specific to the request. The reason the filters are divided by the dotted line is that filters can run logic both before and after the Proxy Request is sent. All “pre” filter logic is executed. Then the proxy request is made Made, the “Post” filter logic is run.

Briefly describes the Filter

  • GatewayFilter: To quote the official documentation, a routing filter is used to modify an incoming HTPP request or HTTP response in a way that applies to a specific route that passes through the SCGFilterFactoryTo create aGatewayFilter.
  • GlobalFilter: To quote the official documentation, the GlobalFilter interface has the same signature as GatewayFilter and is a special filter that applies conditionally to all routes.

It can be seen from the assembly timing and mode of the two filters that the scope of the two filters is different. GatewayFilter binds the Filter corresponding to the configured Filter to the corresponding route during the assembly of CachingRouteLocator. GlobalFilter (all) is assembled when FilteringWebHandler is assembled.

conclusion

At this point, the SCG request flow from access to processing is clear, but it is not clear what the specific role of the Filter is, which Filter is pre and post, and which Filter is used to send the proxy request, we will reveal them in a later article.