Spring cloud upgrade 2020.0.x - 41. Explanation of the basic process of spring cloud gateway

Code address of this series: https://github.com/JoJoTec/sp...

We continue to analyze the WebHandler mentioned in the previous section. After the request is encapsulated into the HttpWebHandlerAdapter of ServerWebExchange, the request will go through exceptionhandling WebHandler

Access point for global Web exception handler - ExceptionHandlingWebHandler

A netizen asked me in a private letter before how to add a global exception handler to the Spring Cloud Gateway. In fact, it is the same as adding a global exception handler to the asynchronous Web service based on spring flux. Both of them implement and register a WebExceptionHandler Bean:

WebExceptionHandler.java

public interface WebExceptionHandler {
    Mono<Void> handle(ServerWebExchange exchange, Throwable ex);
}

These beans are added to the entire request processing link when exceptionhandling webhandler:

ExceptionHandlingWebHandler.java

@Override
public Mono<Void> handle(ServerWebExchange exchange) {
    Mono<Void> completion;
    try {
        //In fact, this is to assemble the later link, that is, to call the handle of the later FilteringWebHandler
        completion = super.handle(exchange);
    }
    catch (Throwable ex) {
        completion = Mono.error(ex);
    }

    for (WebExceptionHandler handler : this.exceptionHandlers) {
        completion = completion.onErrorResume(ex -> handler.handle(exchange, ex));
    }
    return completion;
}

As can be seen from the source code, each WebExceptionHandler is added to the link as Mono's exception handler onErrorResume. onErrorResume means that if an exception occurs in front of the link, the exception will be caught here and handler.handle(exchange, ex) will be called for processing. If the blocking code is used for understanding, it is equivalent to:

try {
    //Front link
} catch(Throwable ex) {
    return handler.handle(exchange, ex)
}

Here we can see that there are multiple webexceptionhandlers that will append onErrorResume after the link, which is actually equivalent to:

completion.onErrorResume(ex -> webExceptionHandler1.handle(exchange, ex)).onErrorResume(ex -> webExceptionHandler2.handle(exchange, ex)).onErrorResume(ex -> webExceptionHandler3.handle(exchange, ex))...

The understanding of converting to blocking code is actually:

try {
    completion
} catch(Throwable e1) {
    try {
        return webExceptionHandler1.handle(exchange, e1)
    } catch(Throwable e2) {
        try {
            return webExceptionHandler2.handle(exchange, ex)
        } catch(Throwable e2) {
            return webExceptionHandler3.handle(exchange, ex)
            //If there is any, continue to stack
        }
    }
}

When WebExceptionHandler can handle this exception, its handle method will return a real response, otherwise it will return an exception, for example:

public class WebExceptionHandler1 implements WebExceptionHandler {
    @Override
    public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {
        //If it is a ResponseStatusException, fill the response code and HTTP header of the response with the response code and HTTP header in the exception
        if (ex instanceof ResponseStatusException) {
            ServerHttpResponse response = exchange.getResponse();
            ResponseStatusException responseStatusException = (ResponseStatusException) ex;
            response.setRawStatusCode(responseStatusException.getRawStatusCode());
            responseStatusException.getResponseHeaders()
                    .forEach((name, values) ->
                            values.forEach(value -> response.getHeaders().add(name, value)));
            //Return response complete
            return response.setComplete();
        }
        //Throw an exception and continue link exception handling
        return Mono.error(ex);
    }
}

Convert to synchronous code to understand, in fact:

if (ex instanceof ResponseStatusException) {
    ServerHttpResponse response = exchange.getResponse();
    ResponseStatusException responseStatusException = (ResponseStatusException) ex;
    response.setRawStatusCode(responseStatusException.getRawStatusCode());
    responseStatusException.getResponseHeaders()
            .forEach((name, values) ->
                    values.forEach(value -> response.getHeaders().add(name, value)));
    //Return response complete
    return response.setComplete();
}
//Throw an exception and continue link exception handling
throw ex;

If you want to encapsulate your own unified error response, you can implement it by implementing this interface.

Link starting point of DefaultWebFilterChain - FilteringWebHandler

Next, enter the FilteringWebHandler. Note that it is org.springframework.web.server.handler.FilteringWebHandler instead of org.springframework.cloud.gateway.handler.FilteringWebHandler of Spring Cloud Gateway. Here, the WebFilter loaded in the context is spliced into DefaultWebFilterChain, and its filter method is called.

private final DefaultWebFilterChain chain;

public FilteringWebHandler(WebHandler handler, List<WebFilter> filters) {
    super(handler);
    this.chain = new DefaultWebFilterChain(handler, filters);
}

@Override
public Mono<Void> handle(ServerWebExchange exchange) {
    return this.chain.filter(exchange);
}

The filtering webhandler of Spring Cloud Gateway is the starting point for Spring Cloud Gateway to process request business. Here we are about to enter the Filter link of the whole Spring Cloud Gateway, including the gateway Filter of each path and the global gateway Filter, which are processed and assembled into a complete call link here. We'll talk about it later

Since our project dependencies include Spring Cloud Sleuth and Prometheus dependencies, our WebFilter here will include three:

  • org.springframework.boot.actuate.metrics.web.reactive.server.MetricsWebFilter: after adding Prometheus related dependencies, this MetricsWebFilter will be used to record the request processing time and collect relevant indicators.
  • org.springframework.cloud.sleuth.instrument.web.TraceWebFilter: after adding Spring Cloud Sleuth related dependencies, there will be this TraceWebFilter.
  • Org.springframework.cloud.gateway.handler.predict.weightcalculatorwebfilter: Spring Cloud Gateway routing weight related configuration function related implementation classes, which we don't care about here.

We will continue to analyze the specific process in detail in the next section.

WeChat search "my programming meow" attention to the official account, daily brush, easy to upgrade technology, and capture all kinds of offer:

Keywords: spring-cloud

Added by EPCtech on Thu, 25 Nov 2021 19:58:59 +0200