环境:Springboot3.0.5
概述RFC 7807定义了为HTTP响应中错误的可读详细信息,以避免需要为HTTP API定义新的错误响应格式。HTTP [RFC7230]状态码有时不足以传达关于错误的足够信息。
(相关资料图)
RFC 7807 定义了简单的JSON[RFC7159]和XML[W3C.REC-XML-20081126]文档格式以满足此目的。它们被设计为可由HTTP API重用,HTTP API可以识别特定于其需求的不同“问题类型”。
因此,API客户端既可以知道高级错误类(使用状态码),也可以知道问题的细粒度细节。
例如,考虑一个响应,该响应表明客户的账户没有足够的权限。403禁止状态代码可能被认为是最适合使用的,因为它将向HTTP通用软件(如客户端库、缓存和代理)通知响应的一般语义。然而,这并没有为API客户端提供足够的信息,说明为什么禁止请求、适用的帐户余额或如何纠正问题。如果这些细节以可读的格式包含在响应体中,则客户端可以适当地处理它;例如触发将更多的信用转移到账户中。
RFC 7807规范通过使用URI[RFC3986]识别特定类型的问题(例如,“信用不足”)来实现这一点;HTTP API可以通过指定受其控制的新URI或重用现有URI来实现这一点。
此外,Problem Detail信息可以包含其他信息,例如标识问题具体发生的URI(有效地为“Joe上周四没有足够的信用”这一概念提供了标识符),这对于支持或取证目的可能很有用。
Problem Detail的数据模型是一个JSON[RFC7159]对象;当格式化为JSON文档时,它使用“application/problem+json”媒体类型。
请注意,Problem Detail 不是在HTTP中传达问题细节的唯一方式;例如,如果响应仍然是资源的表示,那么通常最好以该应用程序的格式来描述相关细节。同样,在许多情况下,有一个适当的HTTP状态代码,不需要传递额外的细节。
Problem Detail消息格式Problem Detail的规范模型是JSON对象。当序列化为JSON文档时,该格式用“application/problem+json”媒体类型标识。
例如,一个带有JSONProblem Detail的HTTP响应:
HTTP/1.1 403 ForbiddenContent-Type: application/problem+jsonContent-Language: en{ "type": "https://pack.com/probs/out-of-credit", "title": "你没有足够的信用。", "detail": "你现在的余额是30,但是要花50。", "instance": "/account/12345/msgs/abc", "balance": 30, "accounts": ["/account/12345", "/account/67890"]}
这里,结余不足问题(由其类型URI标识)
type:标识问题类型的URI引用title:中指明了403的原因instance:给出了具体问题发生的参考detail:中给出了发生的具体细节,并添加了两个扩展balance:表示帐户的余额accounts:提供了可以充值帐户的链接传递问题特定扩展的能力允许传递多个问题。例如:
HTTP/1.1 400 Bad RequestContent-Type: application/problem+jsonContent-Language: en { "type": "https://example.net/validation-error", "title": "Your request parameters didn"t validate.", "invalid-params": [ { "name": "age", "reason": "must be a positive integer" }, { "name": "color", "reason": "must be "green", "red" or "blue"" } ]}
Spring支持从Spring6.x开始支持Problem Detail。
REST服务的一个常见需求是在错误响应的主体中包含详细信息。Spring框架支持“Problem Details for HTTP APIs”规范,即RFC 7807。
以下是此支持的主要抽象:
ProblemDetail — RFC 7807问题细节的表示;一个简单的容器,用于规范中定义的标准字段和非标准字段。ErrorResponse — 以RFC 7807的格式暴露HTTP错误响应细节,包括HTTP状态、响应头和响应体;这允许异常封装并暴露它们如何映射到HTTP响应的细节。所有Spring MVC异常都实现了这一点。ErrorResponseException — 基本的ErrorResponse实现,其他人可以作为一个方便的基类使用。ResponseEntityExceptionHandler — @ControllerAdvice的方便基类,它处理所有Spring MVC异常,以及任何ErrorResponseException,并渲染一个带有主体的错误响应。Spring中要使用ProblemDetail首先需要通过如下配置开启:
spring: mvc: problemdetails: enabled: true
我们可以在任何使用@ExceptionHandler或任何@RequestMapping方法返回ProblemDetail或ErrorResponse以呈现RFC 7807响应。处理方式如下:
ProblemDetail的status属性决定了HTTP的状态。如果还没有设置,则从当前URL路径设置ProblemDetail的实例属性。对于内容协商,Jackson HttpMessageConverter在渲染ProblemDetail时更喜欢“application/problem+json”而不是“application/json”,如果没有找到兼容的媒体类型,也会使用它。要为Spring WebFlux异常和任何ErrorResponseException启用RFC 7807响应,需要扩展ResponseEntityExceptionHandler,并在Spring配置中把它声明为@ControllerAdvice。处理程序有一个@ExceptionHandler方法,可以处理所有ErrorResponse异常,其中包括所有内置的web异常。您可以添加更多的异常处理方法,并使用protected方法将任何异常映射到ProblemDetail。
非标准字段
可以通过以下两种方式之一使用非标准字段扩展RFC7807响应。
一、ProblemDetail类中有个Map集合的"properties"属性。在使用Jackson库时,Spring框架注册了ProblemDetailJacksonMixin,以确保这个“properties”映射被展开,并在响应中作为顶级JSON属性呈现,同样,反序列化期间的任何未知属性都会插入到这个Map中。
你还可以扩展ProblemDetail以添加专用的非标准属性。ProblemDetail中的复制构造函数允许从现有的ProblemDetail中轻松创建子类。这可以集中完成,例如从@ControllerAdvice,如ResponseEntityExceptionHandler,它将异常的ProblemDetail重新创建到一个具有额外非标准字段的子类中。
ProblemDetail类
public class ProblemDetail { private static final URI BLANK_TYPE = URI.create("about:blank"); private URI type = BLANK_TYPE; @Nullable private String title; private int status; @Nullable private String detail; @Nullable private URI instance; @Nullable private Map properties;}
测试接口:
@RestController@RequestMapping("/demo")public class DemoController { @GetMapping("") public Object index(Integer age) { System.out.println(1 / 0) ; return "success" ; } }
示例1:
基础使用
@RestControllerAdvicepublic class GlobalExceptionHandler { // 当发生异常后直接返回ProblemDetail对象 @ExceptionHandler({Exception.class}) public ProblemDetail handle(Exception e) { ProblemDetail detail = ProblemDetail.forStatusAndDetail(HttpStatusCode.valueOf(500), e.getMessage()); return detail ; }}
运行结果:
示例2:
添加扩展属性
@RestControllerAdvicepublic class GlobalExceptionHandler { // 这里使用的是ErrorResponse @ExceptionHandler({ArithmeticException.class}) public ErrorResponse handle(Exception e) { ErrorResponse errorResponse = new ErrorResponseException(HttpStatusCode.valueOf(500), e) ; errorResponse.getBody().setProperty("operator_time", new Date()) ; return errorResponse ; } }
运行结果:
示例3:
继承自ResponseEntityExceptionHandler该类中定义了@ExceptionHandler注解的方法,能够处理大多数常见的异常。
@ControllerAdvicefinal class ProblemDetailsExceptionHandler extends ResponseEntityExceptionHandler {}
ResponseEntityExceptionHandler
public abstract class ResponseEntityExceptionHandler implements MessageSourceAware { @ExceptionHandler({ HttpRequestMethodNotSupportedException.class, HttpMediaTypeNotSupportedException.class, HttpMediaTypeNotAcceptableException.class, MissingPathVariableException.class, MissingServletRequestParameterException.class, MissingServletRequestPartException.class, ServletRequestBindingException.class, MethodArgumentNotValidException.class, NoHandlerFoundException.class, AsyncRequestTimeoutException.class, ErrorResponseException.class, ConversionNotSupportedException.class, TypeMismatchException.class, HttpMessageNotReadableException.class, HttpMessageNotWritableException.class, BindException.class }) @Nullable public final ResponseEntity
该类是Spring提供的默认实现,要使用该类是需要通过如下配置开启:
spring.mvc.problemdetails.enabled=true
处理原理当返回结果是ProblemDetail或者ErrorResponse时通过如下类进行解析处理:
public class HttpEntityMethodProcessor extends AbstractMessageConverterMethodProcessor { public boolean supportsReturnType(MethodParameter returnType) { Class> type = returnType.getParameterType(); return ((HttpEntity.class.isAssignableFrom(type) && !RequestEntity.class.isAssignableFrom(type)) || ErrorResponse.class.isAssignableFrom(type) || ProblemDetail.class.isAssignableFrom(type)); } public void handleReturnValue(...) throws Exception { HttpEntity> httpEntity; if (returnValue instanceof ErrorResponse response) { httpEntity = new ResponseEntity<>(response.getBody(), response.getHeaders(), response.getStatusCode()); } else if (returnValue instanceof ProblemDetail detail) { httpEntity = ResponseEntity.of(detail).build(); } if (httpEntity.getBody() instanceof ProblemDetail detail) { if (detail.getInstance() == null) { URI path = URI.create(inputMessage.getServletRequest().getRequestURI()); detail.setInstance(path); } } // ... writeWithMessageConverters(httpEntity.getBody(), returnType, inputMessage, outputMessage); outputMessage.flush(); }}
以上就是ProblemDetail在Spring中的实现原理。
关键词:
谷子是什么?谷子的形态特征是什么? |
小麦和水稻的区别有哪些?怎么种植水稻? |
水稻的起源是什么?我国最早的水稻是在哪里种植的? |
袁隆平杂交水稻最高亩产多少?最新杂交水稻亩产量有多高? |
农药在土壤中的降解方法有哪些?降解农药最好的途径是什么? |
稻田地下害虫防治的方法有哪些?怎么进行水稻田地下害虫的防治? |
水稻苗床如何测试土壤的PH值?水稻土壤测试方法有哪些? |
水稻除草剂有哪些品种?用什么水稻除草剂药最好? |
磷肥跟复合肥有什么区别?磷肥和复合肥能一起使用吗? |
好消息!郑渝高铁万州至巫山段有望在本月内开通运行 |
重磅!2022年福建省“最美科技工作者”名单正式公布 |
今年高考福建省有21.8万名考生报考 共设221个考点 |
粽盒、粽绳、粽叶和粽馅如何分类?如何做到垃圾准确投放? |
计划到2025年广州农村生活污水处理设施有效运行率不低于90% |
广州大力推进政策兑现集成服务模式 累计办理业务逾3.37万件 |
视焦点讯!山西省运城盐湖保护利用研究院揭牌 |
焦点速看:10对闽台乡村项目签约 台湾专家指两岸合作大有机会 |
住建部:部署2023年乡村建设评价工作|世界最资讯 |
焦点要闻:2023中国农机推广“田间日”培训活动在潍坊举办 |
今日关注:国内多地县域充电桩安装量翻番 呈现哪些新趋势? |
当前速看:喜看麦田千层浪 又到小麦丰收时 |
天天视讯!青海省乡村建设提质推进会暨生活垃圾治理现场会召开 |
全球微头条丨将生态“高颜值”转化为经济“高价值” |
中国热科院湛江站: 4个砂仁新品种获批植物新品种权 世界实时 |
全国麦收进度过九成五 多地采取措施保障夏粮丰收_最资讯 |
种子发芽的条件是什么?种子萌发的主要条件是哪些? |
速生桉是什么植物?速生桉的形态特征是什么? |
大丽花养殖注意事项有哪些?大丽花扦插时间是什么时候? |
大丽花的花语是什么?大丽花的养殖方法是什么? |
迎春花是什么颜色的?迎春花的生长习性是什么? |
种植基地网 版权所有©未经书面授权禁止复制或建立镜像
京ICP备2022022245号-33
联系我们: 435 226 40@qq.com