问题
I have tried all 3 solutions suggested in what is the right way to handle errors in spring-webflux, but WebExceptionHandler
is not getting called. I am using Spring Boot 2.0.0.M7
. Github repo here
@Configuration
class RoutesConfiguration {
@Autowired
private lateinit var testService: TestService
@Autowired
private lateinit var globalErrorHandler: GlobalErrorHandler
@Bean
fun routerFunction():
RouterFunction<ServerResponse> = router {
("/test").nest {
GET("/") {
ServerResponse.ok().body(testService.test())
}
}
}
}
@Component
class GlobalErrorHandler() : WebExceptionHandler {
companion object {
private val log = LoggerFactory.getLogger(GlobalErrorHandler::class.java)
}
override fun handle(exchange: ServerWebExchange?, ex: Throwable?): Mono<Void> {
log.info("inside handle")
/* Handle different exceptions here */
when(ex!!) {
is ClientException -> exchange!!.response.statusCode = HttpStatus.BAD_REQUEST
is Exception -> exchange!!.response.statusCode = HttpStatus.INTERNAL_SERVER_ERROR
}
return Mono.empty()
}
}
UPDATE:
When I change Spring Boot version to 2.0.0.M2
, the WebExceptionHandler
is getting called. Do I need to do something for 2.0.0.M7
?
SOLUTION:
As per Brian's suggestion, it worked as
@Bean
@Order(-2)
fun globalErrorHandler() = GlobalErrorHandler()
回答1:
You can provide your own WebExceptionHandler
, but you have to order it relatively to others, otherwise they might handle the error before yours get a chance to try.
- the
DefaultErrorWebExceptionHandler
provided by Spring Boot for error handling (see reference documentation) is ordered at-1
- the
ResponseStatusExceptionHandler
provided by Spring Framework is ordered at0
So you can add @Order(-2)
on your error handling component, to order it before the existing ones.
回答2:
An error response should have standard payload info. This can be done by extending AbstractErrorWebExceptionHandler
ErrorResponse: Data Class
data class ErrorResponse(
val timestamp: String,
val path: String,
val status: Int,
val error: String,
val message: String
)
ServerResponseBuilder: 2 different methods to build an error response
- default: handle standard errors
webClient: handle
webClient
exceptions (WebClientResponseException
), not for this caseclass ServerResponseBuilder( private val request: ServerRequest, private val status: HttpStatus) { fun default(): Mono<ServerResponse> = ServerResponse .status(status) .body(BodyInserters.fromObject(ErrorResponse( Date().format(), request.path(), status.value(), status.name, status.reasonPhrase))) fun webClient(e: WebClientResponseException): Mono<ServerResponse> = ServerResponse .status(status) .body(BodyInserters.fromObject(ErrorResponse( Date().format(), request.path(), e.statusCode.value(), e.message.toString(), e.responseBodyAsString))) }
GlobalErrorHandlerConfiguration: Error handler
@Configuration
@Order(-2)
class GlobalErrorHandlerConfiguration @Autowired constructor(
errorAttributes: ErrorAttributes,
resourceProperties: ResourceProperties,
applicationContext: ApplicationContext,
viewResolversProvider: ObjectProvider<List<ViewResolver>>,
serverCodecConfigurer: ServerCodecConfigurer) :
AbstractErrorWebExceptionHandler(
errorAttributes,
resourceProperties,
applicationContext
) {
init {
setViewResolvers(viewResolversProvider.getIfAvailable { emptyList() })
setMessageWriters(serverCodecConfigurer.writers)
setMessageReaders(serverCodecConfigurer.readers)
}
override fun getRoutingFunction(errorAttributes: ErrorAttributes?): RouterFunction<ServerResponse> =
RouterFunctions.route(RequestPredicates.all(), HandlerFunction<ServerResponse> { response(it, errorAttributes) })
private fun response(request: ServerRequest, errorAttributes: ErrorAttributes?): Mono<ServerResponse> =
ServerResponseBuilder(request, status(request, errorAttributes)).default()
private fun status(request: ServerRequest, errorAttributes: ErrorAttributes?) =
HttpStatus.valueOf(errorAttributesMap(request, errorAttributes)["status"] as Int)
private fun errorAttributesMap(request: ServerRequest, errorAttributes: ErrorAttributes?) =
errorAttributes!!.getErrorAttributes(request, false)
}
来源:https://stackoverflow.com/questions/47631243/spring-5-reactive-webexceptionhandler-is-not-getting-called