Spring 5 反应性 - WebExceptionHandler 未被调用
Spring 5 Reactive - WebExceptionHandler is not getting called
我已经尝试了 , but WebExceptionHandler
is not getting called. I am using Spring Boot 2.0.0.M7
. Github repo here
中建议的所有 3 种解决方案
@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()
}
}
更新:
当我将 Spring 引导版本更改为 2.0.0.M2
时,将调用 WebExceptionHandler
。我需要为 2.0.0.M7
做些什么吗?
解决方案:
根据布赖恩的建议,它起到了
@Bean
@Order(-2)
fun globalErrorHandler() = GlobalErrorHandler()
您可以提供自己的 WebExceptionHandler
,但您必须相对于其他人订购,否则他们可能会在您有机会尝试之前处理错误。
- 由 Spring 提供的
DefaultErrorWebExceptionHandler
错误处理引导 (see reference documentation) 在 -1
订购
- Spring 框架提供的
ResponseStatusExceptionHandler
在 0
订购
因此您可以在错误处理组件上添加 @Order(-2)
,以便在现有组件之前对其进行排序。
错误响应应该有标准的负载信息。这可以通过扩展 AbstractErrorWebExceptionHandler
来完成
错误响应:数据Class
data class ErrorResponse(
val timestamp: String,
val path: String,
val status: Int,
val error: String,
val message: String
)
ServerResponseBuilder:构建错误响应的 2 种不同方法
- 默认:处理标准错误
webClient:处理webClient
异常(WebClientResponseException
),不适用于这种情况
class 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:错误处理程序
@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)
}
我已经尝试了 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()
}
}
更新:
当我将 Spring 引导版本更改为 2.0.0.M2
时,将调用 WebExceptionHandler
。我需要为 2.0.0.M7
做些什么吗?
解决方案:
根据布赖恩的建议,它起到了
@Bean
@Order(-2)
fun globalErrorHandler() = GlobalErrorHandler()
您可以提供自己的 WebExceptionHandler
,但您必须相对于其他人订购,否则他们可能会在您有机会尝试之前处理错误。
- 由 Spring 提供的
DefaultErrorWebExceptionHandler
错误处理引导 (see reference documentation) 在-1
订购
- Spring 框架提供的
ResponseStatusExceptionHandler
在0
订购
因此您可以在错误处理组件上添加 @Order(-2)
,以便在现有组件之前对其进行排序。
错误响应应该有标准的负载信息。这可以通过扩展 AbstractErrorWebExceptionHandler
错误响应:数据Class
data class ErrorResponse(
val timestamp: String,
val path: String,
val status: Int,
val error: String,
val message: String
)
ServerResponseBuilder:构建错误响应的 2 种不同方法
- 默认:处理标准错误
webClient:处理
webClient
异常(WebClientResponseException
),不适用于这种情况class 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:错误处理程序
@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)
}