Это 25-й день моего участия в ноябрьском испытании обновлений. Узнайте подробности события:Вызов последнего обновления 2021 г.
Кодовый адрес этой серии:GitHub.com/Jojo TE C/SPR...
Продолжаем анализировать то, о чем говорилось в предыдущем разделеWebHandler
, после инкапсуляции запроса в HttpWebHandlerAdapter ServerWebExchange запрос будет проходить через ExceptionHandlingWebHandler.
Точка доступа для обработчика исключений глобальной веб-обработки — ExceptionHandlingWebHandler
Некоторые пользователи сети ранее спрашивали автора в частном порядке, как добавить глобальный обработчик исключений в Spring Cloud Gateway, что на самом деле то же самое, что добавить асинхронный веб-сервис на основе Spring-Flux.путем внедрения и регистрацииWebExceptionHandler
Bean:
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, подписывайтесь на официальный аккаунт, чистите каждый день, легко улучшайте свои технологии и получайте различные предложения.: