Spring 5 Reactive - 没有调用WebExceptionHandler

jak*_*aks 1 exception-handling reactive-programming spring-boot spring-webflux

我已经尝试了所有3个解决方案,建议用什么方法来处理spring-webflux中的错误,但是WebExceptionHandler没有被调用.我在用Spring Boot 2.0.0.M7.Github回复这里

@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()
  }
}
Run Code Online (Sandbox Code Playgroud)

更新:

当我将Spring Boot版本改为时2.0.0.M2,WebExceptionHandler它就被调用了.我需要做点什么2.0.0.M7吗?

解:

按照Brian的建议,它起作用了

@Bean
@Order(-2)
fun globalErrorHandler() = GlobalErrorHandler()
Run Code Online (Sandbox Code Playgroud)

Bri*_*zel 12

您可以提供自己的WebExceptionHandler,但必须相对于其他人订购,否则他们可能会在您有机会尝试之前处理错误.

  • DefaultErrorWebExceptionHandler错误处理(提供由Spring引导见参考文献)在订购-1
  • ResponseStatusExceptionHandler由Spring框架提供的是有序0

因此,您可以添加@Order(-2)错误处理组件,在现有组件之前对其进行排序.


小智 5

错误响应应该具有标准的有效负载信息。这可以通过扩展来完成AbstractErrorWebExceptionHandler

错误响应:数据类

data class ErrorResponse(
    val timestamp: String,
    val path: String,
    val status: Int,
    val error: String,
    val message: String
)
Run Code Online (Sandbox Code Playgroud)

ServerResponseBuilder:两种不同的方法来构建错误响应

  • 默认值:处理标准错误
  • 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)))
    }
    
    Run Code Online (Sandbox Code Playgroud)

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)
}
Run Code Online (Sandbox Code Playgroud)