Дорога обновления SpringCloud 2020.0.x версия 41. Объяснение основного процесса SpringCloudGateway (2)

Java задняя часть Spring Cloud
Дорога обновления SpringCloud 2020.0.x версия 41. Объяснение основного процесса SpringCloudGateway (2)

Это 25-й день моего участия в ноябрьском испытании обновлений. Узнайте подробности события:Вызов последнего обновления 2021 г.

Кодовый адрес этой серии:GitHub.com/Jojo TE C/SPR...

Продолжаем анализировать то, о чем говорилось в предыдущем разделеWebHandler, после инкапсуляции запроса в HttpWebHandlerAdapter ServerWebExchange запрос будет проходить через ExceptionHandlingWebHandler.

image

Точка доступа для обработчика исключений глобальной веб-обработки — ExceptionHandlingWebHandler

Некоторые пользователи сети ранее спрашивали автора в частном порядке, как добавить глобальный обработчик исключений в Spring Cloud Gateway, что на самом деле то же самое, что добавить асинхронный веб-сервис на основе Spring-Flux.путем внедрения и регистрацииWebExceptionHandler Bean:

WebExceptionHandler.java

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

Эти bean-компоненты добавляются во всю цепочку обработки запросов в ExceptionHandlingWebHandler:

ExceptionHandlingWebHandler.java

@Override
public Mono<Void> handle(ServerWebExchange exchange) {
	Mono<Void> completion;
	try {
	    //这里其实就是组装后面的链路,即调用后面的 FilteringWebHandler 的 handle
		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;
}

Как видно из исходного кода, каждыйWebExceptionHandlerОбработка исключений как MonoonErrorResumeДобавлена ​​ссылка.onErrorResumeЭто означает, что если перед ссылкой возникает исключение, то исключение перехватывается здесь и вызывается одновременно.handler.handle(exchange, ex)Обработка, если используется понимание кода блокировки, эквивалентна:

try {
    //前面的链路
} catch(Throwable ex) {
    return handler.handle(exchange, ex)
}

Здесь мы видим, что существует несколькоWebExceptionHandler, будет добавлено после ссылкиonErrorResume, что на самом деле эквивалентно:

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

В переводе на блокировку понимания кода это на самом деле:

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)
            //如果还有就继续叠加
        }
    }
}

Когда WebExceptionHandler может обработать это исключение, егоhandleМетод вернет реальный ответ, иначе вернет исключение, например:

public class WebExceptionHandler1 implements WebExceptionHandler {
	@Override
	public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {
		//如果是 ResponseStatusException 则使用异常里面的响应码和 HTTP 头填充响应的响应码和 HTTP 头
		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.setComplete();
		}
		//抛出异常,继续链路异常处理
		return Mono.error(ex);
	}
}

Преобразованный в синхронный код для понимания на самом деле:

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.setComplete();
}
//抛出异常,继续链路异常处理
throw ex;

Если вы хотите инкапсулировать свой собственный унифицированный ответ об ошибке, вы можете сделать это, реализовав этот интерфейс.

Ссылка на начало DefaultWebFilterChain — FilteringWebHandler

Далее введите FilteringWebHandler, обратите внимание, чтоorg.springframework.web.server.handler.FilteringWebHandlerвместо Spring Cloud Gatewayorg.springframework.cloud.gateway.handler.FilteringWebHandler. Здесь WebFilter, загруженный в контексте, будет сращен наDefaultWebFilterChain, а затем вызовите его метод фильтра:

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);
}

FilteringWebHandler Spring Cloud Gateway, который является отправной точкой для обработки запросов Spring Cloud Gateway. Здесь мы собираемся ввести ссылку «Фильтр» всего Spring Cloud Gateway, включая собственный путь каждого пути.GatewayFilterи глобальныйGlobalGatewayFilter, которые здесь обрабатываются и собираются в полную цепочку вызовов. мы упомянем позже

Поскольку наши проектные зависимости включают Spring Cloud Sleuth и PROMETHEUS Зависимости, наш WebFilter здесь будет включать три:

  • org.springframework.boot.actuate.metrics.web.reactive.server.MetricsWebFilter: После добавления зависимостей, связанных с Prometheus, будет этот MetricsWebFilter, который используется для записи времени обработки запроса и сбора связанных метрик.
  • org.springframework.cloud.sleuth.instrument.web.TraceWebFilter: после добавления зависимостей, связанных с Spring Cloud Sleuth, появится этот TraceWebFilter.
  • org.springframework.cloud.gateway.handler.predicate.WeightCalculatorWebFilter: Spring Cloud Gateway маршрутизация, связанная с весовой конфигурацией, относится к классам реализации, которые нас здесь не интересуют.

Его конкретный процесс мы продолжим подробно анализировать в следующем разделе.

Ищите «My Programming Meow» в WeChat, подписывайтесь на официальный аккаунт, чистите каждый день, легко улучшайте свои технологии и получайте различные предложения.: