Spring Boot升级后REST服务错误响应异常及白标页问题求助
问题根源与解决方案
核心问题1:ErrorMessage构造函数未初始化字段
你的ErrorMessage类中的两个构造函数都是空实现,没有给类的成员变量赋值。比如调用new ErrorMessage("404", e.getMessage(), stackTrace)时,statusCode、message等字段完全没被设置,最终序列化后自然全是默认值(int类型为0,引用类型为null)。
修复构造函数
修改ErrorMessage的构造函数,确保参数正确映射到成员变量:
import java.util.Date; public class ErrorMessage { private int statusCode; @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd-MM-yyyy hh:mm:ss") private Date timestamp; private String message; private String path; private String error; // 针对404场景的构造函数,补充必要字段赋值 public ErrorMessage(int statusCode, Date timestamp, String message, String path, String error) { this.statusCode = statusCode; this.timestamp = timestamp; this.message = message; this.path = path; this.error = error; } // 兼容原有调用的构造函数,补充赋值逻辑 public ErrorMessage(int value, Date date, String message, String resourceNotFound) { this.statusCode = value; this.timestamp = date; this.message = message; this.error = resourceNotFound; } public ErrorMessage(String status, String message, String stackTrace) { this.statusCode = Integer.parseInt(status); this.message = message; this.error = stackTrace; this.timestamp = new Date(); // 自动生成当前时间戳 } // 原有getter/setter保留 public int getStatusCode() { return statusCode; } public void setStatusCode(int statusCode) { this.statusCode = statusCode; } public Date getTimestamp() { return timestamp; } public void setTimestamp(Date timestamp) { this.timestamp = timestamp; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } public String getPath() { return path; } public void setPath(String path) { this.path = path; } public String getError() { return error; } public void setError(String error) { this.error = error; } }
核心问题2:全局异常处理器的缺陷
你的ValidationExceptionHandler存在以下问题:
- 方法参数使用
Exception而非CustomDataNotFoundException,不够精准 - 未获取当前请求的路径(
path字段) - 未设置
timestamp字段 - Spring Boot升级后,默认内容协商机制会根据浏览器
Accept头返回HTML白标页,而非JSON
修复全局异常处理器
改用@RestControllerAdvice(等同于@ControllerAdvice + @ResponseBody,确保返回JSON),同时补充路径和时间戳的获取:
import jakarta.servlet.http.HttpServletRequest; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; import java.io.PrintWriter; import java.io.StringWriter; import java.util.Date; @RestControllerAdvice public class ValidationExceptionHandler { @ExceptionHandler(CustomDataNotFoundException.class) public ResponseEntity<ErrorMessage> handleCustomDataNotFoundExceptions( CustomDataNotFoundException e, HttpServletRequest request ) { HttpStatus status = HttpStatus.NOT_FOUND; // 转换堆栈信息为字符串 StringWriter stringWriter = new StringWriter(); PrintWriter printWriter = new PrintWriter(stringWriter); e.printStackTrace(printWriter); String stackTrace = stringWriter.toString(); // 构造正确的ErrorMessage对象 ErrorMessage errorMessage = new ErrorMessage( status.value(), new Date(), e.getMessage(), request.getRequestURI(), stackTrace ); return new ResponseEntity<>(errorMessage, status); } }
核心问题3:Controller逻辑错误
你的Controller代码中存在永远为false的条件判断:
if (system.isEmpty() && !system.isEmpty()) { // 这段代码永远不会执行 }
这个逻辑矛盾,需要根据实际业务需求修正,比如改为if (system == null || system.isEmpty()),否则相关的异常抛出逻辑永远不会触发。
额外配置:强制所有异常返回JSON(可选)
如果希望浏览器请求时也强制返回JSON而非白标页,可以添加以下配置类,覆盖Spring Boot默认错误处理:
import org.springframework.boot.web.servlet.error.ErrorController; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import jakarta.servlet.http.HttpServletRequest; import java.util.Date; @RestController public class CustomErrorController implements ErrorController { @RequestMapping("/error") public ResponseEntity<ErrorMessage> handleError(HttpServletRequest request) { Object statusObj = request.getAttribute("jakarta.servlet.error.status_code"); int statusCode = statusObj != null ? Integer.parseInt(statusObj.toString()) : HttpStatus.INTERNAL_SERVER_ERROR.value(); String message = (String) request.getAttribute("jakarta.servlet.error.message"); String path = (String) request.getAttribute("jakarta.servlet.error.request_uri"); ErrorMessage errorMessage = new ErrorMessage( statusCode, new Date(), message != null ? message : "An unexpected error occurred", path, "" ); return new ResponseEntity<>(errorMessage, HttpStatus.valueOf(statusCode)); } }
内容的提问来源于stack exchange,提问作者Rose
相关产品推荐
相关产品推荐

