基于Kotlin的Spring WebFlux响应式异常处理器实现遇错求助
Spring WebFlux 异常处理器实现修正方案
问题背景
参照Spring官方文档编写Spring WebFlux异常处理器时出现错误,原始代码如下:
import org.springframework.boot.autoconfigure.web.WebProperties import org.springframework.boot.autoconfigure.web.reactive.error.AbstractErrorWebExceptionHandler import org.springframework.boot.web.reactive.error.ErrorAttributes import org.springframework.context.ApplicationContext import org.springframework.http.HttpStatus import org.springframework.http.MediaType import org.springframework.stereotype.Component import org.springframework.web.reactive.function.server.RouterFunction import org.springframework.web.reactive.function.server.RouterFunctions import org.springframework.web.reactive.function.server.ServerRequest import org.springframework.web.reactive.function.server.ServerResponse import reactor.core.publisher.Mono @Component class MyErrorWebExceptionHandler(errorAttributes: ErrorAttributes?, resources: WebProperties.Resources?, applicationContext: ApplicationContext?) : AbstractErrorWebExceptionHandler(errorAttributes, resources, applicationContext) { override fun getRoutingFunction(errorAttributes: ErrorAttributes): RouterFunction<ServerResponse> { return RouterFunctions.route(this::acceptsXml, this::handleErrorAsXml) } private fun acceptsXml(request: ServerRequest): Boolean { return request.headers().accept().contains(MediaType.APPLICATION_XML) } fun handleErrorAsXml(request: ServerRequest?): Mono<ServerResponse> { val builder = ServerResponse.status(HttpStatus.INTERNAL_SERVER_ERROR) // ... additional builder calls return builder.build() } }
核心修正点
构造函数参数与初始化修正
Spring Boot 2.6+版本中,WebProperties.Resources需通过WebProperties实例获取,且构造参数应使用非空类型(Spring依赖注入会确保实例存在)。同时必须配置消息读写器,避免序列化异常:constructor( errorAttributes: ErrorAttributes, webProperties: WebProperties, applicationContext: ApplicationContext ) : super(errorAttributes, webProperties.resources, applicationContext) { setMessageWriters(ServerCodecConfigurer.create().writers) setMessageReaders(ServerCodecConfigurer.create().readers) }处理方法参数与逻辑完善
handleErrorAsXml的ServerRequest参数不应为可空类型,且需从ErrorAttributes中获取异常详情生成有意义的响应:private fun handleErrorAsXml(request: ServerRequest): Mono<ServerResponse> { val error = getError(request) val status = determineStatus(error) ?: HttpStatus.INTERNAL_SERVER_ERROR val xmlResponse = """ <error> <status>${status.value()}</status> <error>${status.reasonPhrase}</error> <message>${error.message ?: "Unknown error"}</message> </error> """.trimIndent() return ServerResponse.status(status) .contentType(MediaType.APPLICATION_XML) .bodyValue(xmlResponse) }覆盖多响应场景
建议添加默认JSON响应处理,覆盖所有请求格式:override fun getRoutingFunction(errorAttributes: ErrorAttributes): RouterFunction<ServerResponse> { return RouterFunctions.route(this::acceptsXml, this::handleErrorAsXml) .andRoute(RequestPredicates.all(), this::handleErrorAsJson) } private fun handleErrorAsJson(request: ServerRequest): Mono<ServerResponse> { val error = getError(request) val status = determineStatus(error) ?: HttpStatus.INTERNAL_SERVER_ERROR val errorDetails = mapOf( "status" to status.value(), "error" to status.reasonPhrase, "message" to (error.message ?: "Unknown error") ) return ServerResponse.status(status) .contentType(MediaType.APPLICATION_JSON) .bodyValue(errorDetails) }
完整修正代码
import org.springframework.boot.autoconfigure.web.WebProperties import org.springframework.boot.autoconfigure.web.reactive.error.AbstractErrorWebExceptionHandler import org.springframework.boot.web.reactive.error.ErrorAttributes import org.springframework.context.ApplicationContext import org.springframework.http.HttpStatus import org.springframework.http.MediaType import org.springframework.stereotype.Component import org.springframework.web.reactive.function.server.RequestPredicates import org.springframework.web.reactive.function.server.RouterFunction import org.springframework.web.reactive.function.server.RouterFunctions import org.springframework.web.reactive.function.server.ServerRequest import org.springframework.web.reactive.function.server.ServerResponse import org.springframework.web.reactive.function.server.ServerCodecConfigurer import reactor.core.publisher.Mono @Component class MyErrorWebExceptionHandler( errorAttributes: ErrorAttributes, webProperties: WebProperties, applicationContext: ApplicationContext ) : AbstractErrorWebExceptionHandler(errorAttributes, webProperties.resources, applicationContext) { init { setMessageWriters(ServerCodecConfigurer.create().writers) setMessageReaders(ServerCodecConfigurer.create().readers) } override fun getRoutingFunction(errorAttributes: ErrorAttributes): RouterFunction<ServerResponse> { return RouterFunctions.route(this::acceptsXml, this::handleErrorAsXml) .andRoute(RequestPredicates.all(), this::handleErrorAsJson) } private fun acceptsXml(request: ServerRequest): Boolean { return request.headers().accept().contains(MediaType.APPLICATION_XML) } private fun handleErrorAsXml(request: ServerRequest): Mono<ServerResponse> { val error = getError(request) val status = determineStatus(error) ?: HttpStatus.INTERNAL_SERVER_ERROR val xmlResponse = """ <error> <status>${status.value()}</status> <error>${status.reasonPhrase}</error> <message>${error.message ?: "Unknown error"}</message> </error> """.trimIndent() return ServerResponse.status(status) .contentType(MediaType.APPLICATION_XML) .bodyValue(xmlResponse) } private fun handleErrorAsJson(request: ServerRequest): Mono<ServerResponse> { val error = getError(request) val status = determineStatus(error) ?: HttpStatus.INTERNAL_SERVER_ERROR val errorDetails = mapOf( "status" to status.value(), "error" to status.reasonPhrase, "message" to (error.message ?: "Unknown error") ) return ServerResponse.status(status) .contentType(MediaType.APPLICATION_JSON) .bodyValue(errorDetails) } }
内容的提问来源于stack exchange,提问作者Saher Al-Sous
相关产品推荐
相关产品推荐

