spring boot中ErrorWebFluxAutoConfiguration的作用是什么,相信很多沒有經(jīng)驗(yàn)的人對(duì)此束手無策,為此本文總結(jié)了問題出現(xiàn)的原因和解決方法,通過這篇文章希望你能解決這個(gè)問題。
公司主營業(yè)務(wù):成都網(wǎng)站建設(shè)、成都做網(wǎng)站、移動(dòng)網(wǎng)站開發(fā)等業(yè)務(wù)。幫助企業(yè)客戶真正實(shí)現(xiàn)互聯(lián)網(wǎng)宣傳,提高企業(yè)的競爭能力。創(chuàng)新互聯(lián)是一支青春激揚(yáng)、勤奮敬業(yè)、活力青春激揚(yáng)、勤奮敬業(yè)、活力澎湃、和諧高效的團(tuán)隊(duì)。公司秉承以“開放、自由、嚴(yán)謹(jǐn)、自律”為核心的企業(yè)文化,感謝他們對(duì)我們的高要求,感謝他們從不同領(lǐng)域給我們帶來的挑戰(zhàn),讓我們激情的團(tuán)隊(duì)有機(jī)會(huì)用頭腦與智慧不斷的給客戶帶來驚喜。創(chuàng)新互聯(lián)推出長洲免費(fèi)做網(wǎng)站回饋大家。
spring-boot-autoconfigure-2.1.5.RELEASE-sources.jar!/org/springframework/boot/autoconfigure/web/reactive/error/ErrorWebFluxAutoConfiguration.java
@Configuration @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE) @ConditionalOnClass(WebFluxConfigurer.class) @AutoConfigureBefore(WebFluxAutoConfiguration.class) @EnableConfigurationProperties({ ServerProperties.class, ResourceProperties.class }) public class ErrorWebFluxAutoConfiguration { private final ServerProperties serverProperties; private final ApplicationContext applicationContext; private final ResourceProperties resourceProperties; private final ListviewResolvers; private final ServerCodecConfigurer serverCodecConfigurer; public ErrorWebFluxAutoConfiguration(ServerProperties serverProperties, ResourceProperties resourceProperties, ObjectProvider viewResolversProvider, ServerCodecConfigurer serverCodecConfigurer, ApplicationContext applicationContext) { this.serverProperties = serverProperties; this.applicationContext = applicationContext; this.resourceProperties = resourceProperties; this.viewResolvers = viewResolversProvider.orderedStream() .collect(Collectors.toList()); this.serverCodecConfigurer = serverCodecConfigurer; } @Bean @ConditionalOnMissingBean(value = ErrorWebExceptionHandler.class, search = SearchStrategy.CURRENT) @Order(-1) public ErrorWebExceptionHandler errorWebExceptionHandler( ErrorAttributes errorAttributes) { DefaultErrorWebExceptionHandler exceptionHandler = new DefaultErrorWebExceptionHandler( errorAttributes, this.resourceProperties, this.serverProperties.getError(), this.applicationContext); exceptionHandler.setViewResolvers(this.viewResolvers); exceptionHandler.setMessageWriters(this.serverCodecConfigurer.getWriters()); exceptionHandler.setMessageReaders(this.serverCodecConfigurer.getReaders()); return exceptionHandler; } @Bean @ConditionalOnMissingBean(value = ErrorAttributes.class, search = SearchStrategy.CURRENT) public DefaultErrorAttributes errorAttributes() { return new DefaultErrorAttributes( this.serverProperties.getError().isIncludeException()); } }
ErrorWebFluxAutoConfiguration注冊(cè)了DefaultErrorAttributes、ErrorWebExceptionHandler
spring-boot-2.1.5.RELEASE-sources.jar!/org/springframework/boot/web/reactive/error/ErrorAttributes.java
public interface ErrorAttributes { /** * Return a {@link Map} of the error attributes. The map can be used as the model of * an error page, or returned as a {@link ServerResponse} body. * @param request the source request * @param includeStackTrace if stack trace elements should be included * @return a map of error attributes */ MapgetErrorAttributes(ServerRequest request, boolean includeStackTrace); /** * Return the underlying cause of the error or {@code null} if the error cannot be * extracted. * @param request the source ServerRequest * @return the {@link Exception} that caused the error or {@code null} */ Throwable getError(ServerRequest request); /** * Store the given error information in the current {@link ServerWebExchange}. * @param error the {@link Exception} that caused the error * @param exchange the source exchange */ void storeErrorInformation(Throwable error, ServerWebExchange exchange); }
ErrorAttributes接口定義了getErrorAttributes、getError、storeErrorInformation三個(gè)方法
spring-boot-2.1.5.RELEASE-sources.jar!/org/springframework/boot/web/reactive/error/DefaultErrorAttributes.java
public class DefaultErrorAttributes implements ErrorAttributes { private static final String ERROR_ATTRIBUTE = DefaultErrorAttributes.class.getName() + ".ERROR"; private final boolean includeException; /** * Create a new {@link DefaultErrorAttributes} instance that does not include the * "exception" attribute. */ public DefaultErrorAttributes() { this(false); } /** * Create a new {@link DefaultErrorAttributes} instance. * @param includeException whether to include the "exception" attribute */ public DefaultErrorAttributes(boolean includeException) { this.includeException = includeException; } @Override public MapgetErrorAttributes(ServerRequest request, boolean includeStackTrace) { Map errorAttributes = new LinkedHashMap<>(); errorAttributes.put("timestamp", new Date()); errorAttributes.put("path", request.path()); Throwable error = getError(request); HttpStatus errorStatus = determineHttpStatus(error); errorAttributes.put("status", errorStatus.value()); errorAttributes.put("error", errorStatus.getReasonPhrase()); errorAttributes.put("message", determineMessage(error)); handleException(errorAttributes, determineException(error), includeStackTrace); return errorAttributes; } private HttpStatus determineHttpStatus(Throwable error) { if (error instanceof ResponseStatusException) { return ((ResponseStatusException) error).getStatus(); } ResponseStatus responseStatus = AnnotatedElementUtils .findMergedAnnotation(error.getClass(), ResponseStatus.class); if (responseStatus != null) { return responseStatus.code(); } return HttpStatus.INTERNAL_SERVER_ERROR; } private String determineMessage(Throwable error) { if (error instanceof WebExchangeBindException) { return error.getMessage(); } if (error instanceof ResponseStatusException) { return ((ResponseStatusException) error).getReason(); } ResponseStatus responseStatus = AnnotatedElementUtils .findMergedAnnotation(error.getClass(), ResponseStatus.class); if (responseStatus != null) { return responseStatus.reason(); } return error.getMessage(); } private Throwable determineException(Throwable error) { if (error instanceof ResponseStatusException) { return (error.getCause() != null) ? error.getCause() : error; } return error; } private void addStackTrace(Map errorAttributes, Throwable error) { StringWriter stackTrace = new StringWriter(); error.printStackTrace(new PrintWriter(stackTrace)); stackTrace.flush(); errorAttributes.put("trace", stackTrace.toString()); } private void handleException(Map errorAttributes, Throwable error, boolean includeStackTrace) { if (this.includeException) { errorAttributes.put("exception", error.getClass().getName()); } if (includeStackTrace) { addStackTrace(errorAttributes, error); } if (error instanceof BindingResult) { BindingResult result = (BindingResult) error; if (result.hasErrors()) { errorAttributes.put("errors", result.getAllErrors()); } } } @Override public Throwable getError(ServerRequest request) { return (Throwable) request.attribute(ERROR_ATTRIBUTE) .orElseThrow(() -> new IllegalStateException( "Missing exception attribute in ServerWebExchange")); } @Override public void storeErrorInformation(Throwable error, ServerWebExchange exchange) { exchange.getAttributes().putIfAbsent(ERROR_ATTRIBUTE, error); } }
DefaultErrorAttributes實(shí)現(xiàn)了ErrorAttributes接口,它的getErrorAttributes方法會(huì)返回timestamp、path、status、error、message、exception(includeException
)、trace(includeStackTrace
)等信息;getError方法會(huì)從ServerRequest的ERROR_ATTRIBUTE中獲取Throwable;storeErrorInformation則是把Throwable存放到ServerWebExchange的attributes中
spring-web-5.1.7.RELEASE-sources.jar!/org/springframework/web/server/WebExceptionHandler.java
public interface WebExceptionHandler { /** * Handle the given exception. A completion signal through the return value * indicates error handling is complete while an error signal indicates the * exception is still not handled. * @param exchange the current exchange * @param ex the exception to handle * @return {@code Mono} to indicate when exception handling is complete */ Mono handle(ServerWebExchange exchange, Throwable ex); }
WebExceptionHandler定義了handle方法
spring-boot-2.1.5.RELEASE-sources.jar!/org/springframework/boot/web/reactive/error/ErrorWebExceptionHandler.java
@FunctionalInterface public interface ErrorWebExceptionHandler extends WebExceptionHandler { }
ErrorWebExceptionHandler繼承了WebExceptionHandler接口,僅僅是通過類名來標(biāo)識(shí)它用來render errors
public abstract class AbstractErrorWebExceptionHandler implements ErrorWebExceptionHandler, InitializingBean { /** * Currently duplicated from Spring WebFlux HttpWebHandlerAdapter. */ private static final SetDISCONNECTED_CLIENT_EXCEPTIONS; static { Set exceptions = new HashSet<>(); exceptions.add("AbortedException"); exceptions.add("ClientAbortException"); exceptions.add("EOFException"); exceptions.add("EofException"); DISCONNECTED_CLIENT_EXCEPTIONS = Collections.unmodifiableSet(exceptions); } private static final Log logger = HttpLogging .forLogName(AbstractErrorWebExceptionHandler.class); private final ApplicationContext applicationContext; private final ErrorAttributes errorAttributes; private final ResourceProperties resourceProperties; private final TemplateAvailabilityProviders templateAvailabilityProviders; private List > messageReaders = Collections.emptyList(); private List > messageWriters = Collections.emptyList(); private List viewResolvers = Collections.emptyList(); public AbstractErrorWebExceptionHandler(ErrorAttributes errorAttributes, ResourceProperties resourceProperties, ApplicationContext applicationContext) { Assert.notNull(errorAttributes, "ErrorAttributes must not be null"); Assert.notNull(resourceProperties, "ResourceProperties must not be null"); Assert.notNull(applicationContext, "ApplicationContext must not be null"); this.errorAttributes = errorAttributes; this.resourceProperties = resourceProperties; this.applicationContext = applicationContext; this.templateAvailabilityProviders = new TemplateAvailabilityProviders( applicationContext); } //...... @Override public void afterPropertiesSet() throws Exception { if (CollectionUtils.isEmpty(this.messageWriters)) { throw new IllegalArgumentException("Property 'messageWriters' is required"); } } /** * Create a {@link RouterFunction} that can route and handle errors as JSON responses * or HTML views. * * If the returned {@link RouterFunction} doesn't route to a {@code HandlerFunction}, * the original exception is propagated in the pipeline and can be processed by other * {@link org.springframework.web.server.WebExceptionHandler}s. * @param errorAttributes the {@code ErrorAttributes} instance to use to extract error * information * @return a {@link RouterFunction} that routes and handles errors */ protected abstract RouterFunction
getRoutingFunction( ErrorAttributes errorAttributes); @Override public Mono handle(ServerWebExchange exchange, Throwable throwable) { if (exchange.getResponse().isCommitted() || isDisconnectedClientError(throwable)) { return Mono.error(throwable); } this.errorAttributes.storeErrorInformation(throwable, exchange); ServerRequest request = ServerRequest.create(exchange, this.messageReaders); return getRoutingFunction(this.errorAttributes).route(request) .switchIfEmpty(Mono.error(throwable)) .flatMap((handler) -> handler.handle(request)) .doOnNext((response) -> logError(request, response, throwable)) .flatMap((response) -> write(exchange, response)); } //...... }
AbstractErrorWebExceptionHandler聲明實(shí)現(xiàn)ErrorWebExceptionHandler以及InitializingBean接口;其handle方法首先把throwable存儲(chǔ)到errorAttributes匯總,然后通過getRoutingFunction進(jìn)行route;afterPropertiesSet主要是確保messageWriters不為空;它定義了getRoutingFunction要子類去實(shí)現(xiàn)
spring-boot-autoconfigure-2.1.5.RELEASE-sources.jar!/org/springframework/boot/autoconfigure/web/reactive/error/DefaultErrorWebExceptionHandler.java
public class DefaultErrorWebExceptionHandler extends AbstractErrorWebExceptionHandler { private static final MapSERIES_VIEWS; static { Map views = new EnumMap<>(HttpStatus.Series.class); views.put(HttpStatus.Series.CLIENT_ERROR, "4xx"); views.put(HttpStatus.Series.SERVER_ERROR, "5xx"); SERIES_VIEWS = Collections.unmodifiableMap(views); } private final ErrorProperties errorProperties; /** * Create a new {@code DefaultErrorWebExceptionHandler} instance. * @param errorAttributes the error attributes * @param resourceProperties the resources configuration properties * @param errorProperties the error configuration properties * @param applicationContext the current application context */ public DefaultErrorWebExceptionHandler(ErrorAttributes errorAttributes, ResourceProperties resourceProperties, ErrorProperties errorProperties, ApplicationContext applicationContext) { super(errorAttributes, resourceProperties, applicationContext); this.errorProperties = errorProperties; } @Override protected RouterFunction getRoutingFunction( ErrorAttributes errorAttributes) { return route(acceptsTextHtml(), this::renderErrorView).andRoute(all(), this::renderErrorResponse); } /** * Render the error information as an HTML view. * @param request the current request * @return a {@code Publisher} of the HTTP response */ protected Mono renderErrorView(ServerRequest request) { boolean includeStackTrace = isIncludeStackTrace(request, MediaType.TEXT_HTML); Map error = getErrorAttributes(request, includeStackTrace); HttpStatus errorStatus = getHttpStatus(error); ServerResponse.BodyBuilder responseBody = ServerResponse.status(errorStatus) .contentType(MediaType.TEXT_HTML); return Flux .just("error/" + errorStatus.value(), "error/" + SERIES_VIEWS.get(errorStatus.series()), "error/error") .flatMap((viewName) -> renderErrorView(viewName, responseBody, error)) .switchIfEmpty(this.errorProperties.getWhitelabel().isEnabled() ? renderDefaultErrorView(responseBody, error) : Mono.error(getError(request))) .next(); } /** * Render the error information as a JSON payload. * @param request the current request * @return a {@code Publisher} of the HTTP response */ protected Mono renderErrorResponse(ServerRequest request) { boolean includeStackTrace = isIncludeStackTrace(request, MediaType.ALL); Map error = getErrorAttributes(request, includeStackTrace); return ServerResponse.status(getHttpStatus(error)) .contentType(MediaType.APPLICATION_JSON_UTF8) .body(BodyInserters.fromObject(error)); } /** * Determine if the stacktrace attribute should be included. * @param request the source request * @param produces the media type produced (or {@code MediaType.ALL}) * @return if the stacktrace attribute should be included */ protected boolean isIncludeStackTrace(ServerRequest request, MediaType produces) { ErrorProperties.IncludeStacktrace include = this.errorProperties .getIncludeStacktrace(); if (include == ErrorProperties.IncludeStacktrace.ALWAYS) { return true; } if (include == ErrorProperties.IncludeStacktrace.ON_TRACE_PARAM) { return isTraceEnabled(request); } return false; } /** * Get the HTTP error status information from the error map. * @param errorAttributes the current error information * @return the error HTTP status */ protected HttpStatus getHttpStatus(Map errorAttributes) { int statusCode = (int) errorAttributes.get("status"); return HttpStatus.valueOf(statusCode); } /** * Predicate that checks whether the current request explicitly support * {@code "text/html"} media type. * * The "match-all" media type is not considered here. * @return the request predicate */ protected RequestPredicate acceptsTextHtml() { return (serverRequest) -> { try { List
acceptedMediaTypes = serverRequest.headers().accept(); acceptedMediaTypes.remove(MediaType.ALL); MediaType.sortBySpecificityAndQuality(acceptedMediaTypes); return acceptedMediaTypes.stream() .anyMatch(MediaType.TEXT_HTML::isCompatibleWith); } catch (InvalidMediaTypeException ex) { return false; } }; } }
DefaultErrorWebExceptionHandler繼承了AbstractErrorWebExceptionHandler;其getRoutingFunction方法會(huì)對(duì)acceptsTextHtml的renderErrorView,其他的通過renderErrorResponse來返回json格式的錯(cuò)誤信息
spring-web-5.1.7.RELEASE-sources.jar!/org/springframework/web/server/handler/ExceptionHandlingWebHandler.java
public class ExceptionHandlingWebHandler extends WebHandlerDecorator { private final ListexceptionHandlers; public ExceptionHandlingWebHandler(WebHandler delegate, List handlers) { super(delegate); this.exceptionHandlers = Collections.unmodifiableList(new ArrayList<>(handlers)); } /** * Return a read-only list of the configured exception handlers. */ public List getExceptionHandlers() { return this.exceptionHandlers; } @Override public Mono handle(ServerWebExchange exchange) { Mono completion; try { 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; } }
ExceptionHandlingWebHandler繼承了WebHandlerDecorator,它會(huì)挨個(gè)調(diào)用WebExceptionHandler的handle方法
ErrorWebFluxAutoConfiguration注冊(cè)了DefaultErrorAttributes、ErrorWebExceptionHandler
DefaultErrorAttributes實(shí)現(xiàn)了ErrorAttributes接口,它的getErrorAttributes方法會(huì)返回timestamp、path、status、error、message、exception(includeException
)、trace(includeStackTrace
)等信息;getError方法會(huì)從ServerRequest的ERROR_ATTRIBUTE中獲取Throwable;storeErrorInformation則是把Throwable存放到ServerWebExchange的attributes中
DefaultErrorWebExceptionHandler繼承了AbstractErrorWebExceptionHandler;其getRoutingFunction方法會(huì)對(duì)acceptsTextHtml的renderErrorView,其他的通過renderErrorResponse來返回json格式的錯(cuò)誤信息
看完上述內(nèi)容,你們掌握spring boot中ErrorWebFluxAutoConfiguration的作用是什么的方法了嗎?如果還想學(xué)到更多技能或想了解更多相關(guān)內(nèi)容,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝各位的閱讀!