一直依赖 Spring Boot 默认的异常反馈内容比较单一,包含 Http Status Code, 时间,异常信息。但具体异常原因没有体现。这次 Spring Boot3对错误信息增强了。
RFC7807
RFC 7807 (Problem Details for HTTP APIs) : RFC 7807: Problem Details for HTTP APIs (rfc-editor.org)
RESTFul 服务中通常需要在响应体中包含错误详情,Spring 框架支持”Problem Details“。定义了Http 应答错误的处理细节,增强了响应错误的内容。包含标准和非标准的字段。同时支持 json 和 xm 两种格式。
基于 Http 协议的请求,可通过 Htp Status Code 分析响应结果,200 为成功, 4XX 为客户端错误,500 是服务器程序代码异常。status code 过于简单,不能进一步说明具体的错误原因和解决途径。比如 http status code 403.但并不能说明”是什么导致了 403“,以及如何解决问题。Http 状态代码可帮助我们区分错误和成功状态,但没法区分得太细致。RFC7807中对这些做了规范的定义。
配置文件
product:
books:
- isbn: book01
name: java
author: lisi
- isbn: book02
name: tomcat
author: zhangsan
- isbn: book03
name: mybatis
author: wangwu
# 访问地址
server:
servlet:
context-path: /api
# 开启RFC 7807
spring:
mvc:
problemdetails:
enabled: true
springboot支持ProblemDetail
controller
@RestController
public class BookController {
//注入BookContainer
@Autowired
private BookContainer bookContainer;
@GetMapping("/book")
public BookRecord getBook(String isbn){
Optional<BookRecord> bookRecord = bookContainer.getBooks().stream().filter(el ->
el.isbn().equals(isbn)
).findFirst();
if(bookRecord.isEmpty()){
throw new BookNotFoundException("isbn:" + isbn + "->没有此图书");
}
return bookRecord.get();
}
}
pojo
public record BookRecord(String isbn, String name, String author) {
}
config
@Setter
@Getter
@ConfigurationProperties(prefix = "product")
public class BookContainer {
private List<BookRecord> books;
}
exception
public class BookNotFoundException extends RuntimeException{
public BookNotFoundException() {
super();
}
public BookNotFoundException(String message) {
super(message);
}
}
handler(处理异常)
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler({BookNotFoundException.class})
public ProblemDetail handlerBookNotFoundException(BookNotFoundException e){
//创建对象
ProblemDetail problemDetail = ProblemDetail.forStatusAndDetail(HttpStatus.NOT_FOUND, e.getMessage());
//设置值
problemDetail.setType(URI.create("/api/probs/not_find"));
problemDetail.setTitle("图书异常");
//自定义字段
problemDetail.setProperty("时间", Instant.now());
return problemDetail;
}
}
启动类
@EnableConfigurationProperties({BookContainer.class})
@SpringBootApplication
public class Lesson12ProblemDetailApplication {
public static void main(String[] args) {
SpringApplication.run(Lesson12ProblemDetailApplication.class, args);
}
}
ErrorResponse
Spring Boot 识别ErrorResponse 类型作为异常的应答结果可以直接使用 ErrorResponse 作为异常处理方法的返回值,ErrorResponseException 是 ErrorResponse 的基本实现类
config, pojo, controller同上
exp
public class IsbnNotFoundException extends ErrorResponseException {
public IsbnNotFoundException(HttpStatus httpStatus, String detail){
super(httpStatus, createProblemDetail(httpStatus, detail), null);
}
private static ProblemDetail createProblemDetail(HttpStatus status, String detail){
//封装
ProblemDetail problemDetail = ProblemDetail.forStatus(status);
problemDetail.setType(URI.create("/api/probs/not-find"));
problemDetail.setTitle("图书异常");
problemDetail.setDetail(detail);
//自定义字段
problemDetail.setProperty("严重程度", "低");
return problemDetail;
}
}
handler
public class GlobalExceptionHandler {
@ExceptionHandler({BookNotFoundException.class})
public ErrorResponse handlerException(BookNotFoundException e){
ErrorResponse errorResponse = new ErrorResponseException(HttpStatus.NOT_FOUND, e);
return errorResponse;
}
}
错误信息
{
"type": "/api/probs/not-find",
"title": "图书异常",
"status": 404,
"detail": "isbn:book06->没有此图书",
"instance": "/api/book",
"严重程度": "低"
}