Skip to content

Instantly share code, notes, and snippets.

@realimp
Created December 30, 2023 14:10
Show Gist options
  • Save realimp/089b5bad3ac90cd1444e2e9771fc679b to your computer and use it in GitHub Desktop.
Save realimp/089b5bad3ac90cd1444e2e9771fc679b to your computer and use it in GitHub Desktop.
Spring WebFlux global exception handling
@Component
@Order(-2)
public class GlobalWebExceptionHandler extends AbstractErrorWebExceptionHandler {
private final Logger logger = LoggerFactory.getLogger(GlobalWebExceptionHandler.class);
public GlobalWebExceptionHandler(ErrorAttributes errorAttributes, WebProperties.Resources resources,
ApplicationContext applicationContext,
ServerCodecConfigurer configurer) {
super(errorAttributes, resources, applicationContext);
this.setMessageWriters(configurer.getWriters());
}
@Override
protected RouterFunction<ServerResponse> getRoutingFunction(ErrorAttributes errorAttributes) {
return RouterFunctions.route(RequestPredicates.all(), this::renderErrorResponse);
}
private Mono<ServerResponse> renderErrorResponse(ServerRequest request) {
Throwable thrown = getError(request);
HttpStatusCode statusCode = HttpStatus.INTERNAL_SERVER_ERROR;
ApiError apiError = new ApiError("Внутренняя ошибка приложения", thrown.getMessage());
if (thrown instanceof ResponseStatusException) {
statusCode = ((ErrorResponse) thrown).getStatusCode();
String message = switch (statusCode.value()) {
case 400 -> "Не корректный запрос";
case 404 -> "Не найдено";
case 405 -> "Метод не поддерживается";
case 406 -> "Тип данных не поддерживается";
case 409 -> "Конфликт";
case 413 -> "Превышен максимальный размер запроса";
case 415 -> "Не поддерживаемый тип данных";
default -> HttpStatus.valueOf(statusCode.value()).getReasonPhrase();
};
if (thrown instanceof WebExchangeBindException) {
apiError = new ApiError(message, getDetails((WebExchangeBindException) thrown));
} else {
apiError = new ApiError(message, ((ResponseStatusException) thrown).getReason());
}
} else if (thrown instanceof ApiException) {
statusCode = ((ApiException) thrown).getStatus();
apiError = new ApiError(((ApiException) thrown).getReason(), thrown.getMessage());
} else {
logger.error("Unexpected error.", thrown);
}
return ServerResponse.status(statusCode)
.header(HttpHeaders.CONNECTION, "close")
.contentType(MediaType.APPLICATION_JSON)
.body(BodyInserters.fromValue(apiError));
}
private static String getDetails(WebExchangeBindException thrown) {
String details = null;
FieldError fieldError = thrown.getFieldError();
ObjectError globalError = thrown.getGlobalError();
if (fieldError != null) {
details = MessageFormat
.format("{0} {1}", fieldError.getField(), fieldError.getDefaultMessage());
} else if (globalError != null) {
details = MessageFormat
.format("{0} {1}", globalError.getObjectName(), globalError.getDefaultMessage());
}
return details;
}
}
import org.springframework.boot.autoconfigure.web.WebProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class WebExceptionHandlingConfiguration {
@Bean
public WebProperties.Resources resources() {
return new WebProperties.Resources();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment