SpringBoot Restful API 自定义错误响应格式

通常我们会通过spring的异常处理器来自定义响应格式,即通过@RestControllerAdvice来实现,但是如果只是为了自定义一个返回格式的话有更好的选择,那就是自定义ErrorController,所有未被处理的异常都会被它处理,@RestControllerAdvice也被视为异常处理,即被@RestControllerAdvice处理的异常将不会到达这里,直接上代码,以Kotlin为例

@RestController
@RequestMapping("/error")
class GlobalErrorController : ErrorController {

    @Autowired
    lateinit var errorAttributes: ErrorAttributes

    @GetMapping
    fun error(request: HttpServletRequest): ResponseEntity<ErrorResponse> {
        val ex: Throwable? = errorAttributes.getError(ServletWebRequest(request))
        val status = getStatus(request)
        return ResponseEntity.status(status)
            .body(ErrorResponse(status = status.name, message = ex?.localizedMessage ?: ""))
    }

    private fun getStatus(request: HttpServletRequest): HttpStatus {
        val statusCode = request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE)

        if (statusCode !is Int) {
            return HttpStatus.INTERNAL_SERVER_ERROR
        }

        return try {
            HttpStatus.valueOf(statusCode)
        } catch (e: Exception) {
            HttpStatus.INTERNAL_SERVER_ERROR
        }
    }
}
  • 这里注入了一个ErrorAttributes类型的bean,它包含了请求上下文的错误信息,通过getError方法可以获取到异常类

  • 匹配到路由/error的方法的返回值会作为响应发送到客户端,当然这个路由是可以自定义的

需要注意的是,如果配置spring.mvc.throw-exception-if-no-handler-foundfalse,由于404不会引发异常,所以通过getError方法获取到的异常将会为null。同时@RestControllerAdvice将不起作用,因为它只会捕获异常,这也是其相比ErrorController的劣势

PS:异常处理的顺序为 主动捕获异常->@RestControllerAdvice->ErrorController->Servlet容器,如Tomcat。被处理过的异常将不会到达下一级