我已尝试在what is the right way to handle errors in spring-webflux中建议的所有3个解决方案,但WebExceptionHandler
未被调用。我正在使用Spring Boot 2.0.0.M7
。 Github回购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 Boot版本更改为2.0.0.M2
时,WebExceptionHandler
将被调用。我需要为2.0.0.M7
做些什么吗?
SOLUTION:
根据Brian的建议,它可以作为
@Bean
@Order(-2)
fun globalErrorHandler() = GlobalErrorHandler()
答案 0 :(得分:11)
您可以提供自己的WebExceptionHandler
,但是您必须相对于其他人订购,否则他们可能会在您有机会尝试之前处理错误。
DefaultErrorWebExceptionHandler
错误处理(see reference documentation)在-1
订购ResponseStatusExceptionHandler
是0
因此,您可以在错误处理组件上添加@Order(-2)
,以便在现有组件之前对其进行排序。
答案 1 :(得分:2)
错误响应应具有标准有效内容信息。这可以通过扩展AbstractErrorWebExceptionHandler
ErrorResponse :数据类
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)
}