当HTTP状态代码不足时:处理Web API错误报告

RESTful Web API设计的一个领域(经常被忽视)是如何报告与业务或应用程序有关的错误和问题。 首先要想到HTTP状态代码的正确用法,尽管它非常方便,但通常它的信息量还不够。 让我们以400错误请求为例。 是的,它清楚地表明请求是有问题的,但是究竟出了什么问题呢?

RESTful的体系结构风格并不决定在这种情况下应该做什么,因此每个人都在发明自己的风格,约定和规范。 它可能像将错误消息包含到响应中一样简单,也可能像复制/粘贴长堆栈跟踪记录一样是短视的(对于Java或.NET,仅举几例)。 并不缺乏想法,但是幸运的是,我们至少有一些以RFC 7807形式提供的指南:HTTP API的问题详细信息 。 尽管它不是官方规范,而是草案(仍然),但它概述了有关当前问题的良好通用原则,这就是我们在本文中要讨论的内容。

简而言之, RFC 7807:HTTP API的问题详细信息仅提出了错误或问题表示形式( JSON或XML格式),其中可能至少包括以下详细信息:

  • type –标识问题类型的URI参考
  • 标题 –问题类型的简短易读摘要
  • status – HTTP状态代码
  • 详细信息 –针对此问题的发生的易于理解的解释
  • 实例 –标识问题特定发生的URI参考

更重要的是,问题类型定义可以使用其他成员扩展问题详细信息对象,从而为上述成员做出贡献。 如您所见,从实现角度看,它看起来非常简单。 更好的是,感谢
Zalando ,我们已经有了
RFC 7807:HTTP API实现的问题详细信息 对于Java (和 特别是Spring Web )。 所以……让我们尝试一下!

我们将使用最新的技术堆栈, Spring Boot和Apache CXF ,流行的Web服务框架和JAX-RS 2.1实现来构建我们虚构的People Management Web API。 为了简单起见,仅公开了两个端点:注册和按人员标识符查找。

Web API错误

撇开开发现实世界服务时可能遇到的大量问题和业务约束,即使使用此简单的API,也可能会出错。 我们要解决的第一个问题是,如果您要寻找的人尚未注册怎么办? 看起来很适合404 Not Found ,对吗? 确实,让我们从第一个问题PersonNotFoundProblem开始

public class PersonNotFoundProblem extends AbstractThrowableProblem {private static final long serialVersionUID = 7662154827584418806L;private static final URI TYPE = URI.create("http://localhost:21020/problems/person-not-found");public PersonNotFoundProblem(final String id, final URI instance) {super(TYPE, "Person is not found", Status.NOT_FOUND, "Person with identifier '" + id + "' is not found", instance, null, Map.of("id", id));}
}

它非常类似于典型的Java异常,并且确实是一个,因为AbstractThrowableProblemRuntimeException的子类。 这样,我们可以从JAX-RS API中抛出它。

@Produces({ MediaType.APPLICATION_JSON, "application/problem+json" })
@GET
@Path("{id}")
public Person findById(@PathParam("id") String id) {return service.findById(id).orElseThrow(() -> new PersonNotFoundProblem(id, uriInfo.getRequestUri()));
}

如果我们运行服务器并尝试获取提供任何标识符的人员,则将返回问题详细信息响应(因为未预先填充数据集),例如:

$ curl "http://localhost:21020/api/people/1" -H  "Accept: */*" HTTP/1.1 404
Content-Type: application/problem+json{"type" : "http://localhost:21020/problems/person-not-found","title" : "Person is not found","status" : 404,"detail" : "Person with identifier '1' is not found","instance" : "http://localhost:21020/api/people/1","id" : "1"
}

请注意应用程序/问题+ json媒体类型的用法以及响应中包含的其他属性ID 。 尽管有许多可以改进的地方,但是可以说它比仅裸露的404 (或由EntityNotFoundException引起的500 )要好。 另外,如果需要进一步的说明,可以参考此类问题背后的文档部分(在我们的情况下为http:// localhost:21020 / problems / person-not-found )。

因此,在例外之后设计问题只是一种选择。 您可能经常(出于非常正当的理由)会避免将业务逻辑与无关的细节耦合在一起。 在这种情况下,返回问题详细信息作为JAX-RS资源的响应有效负载是完全有效的。 例如,注册过程可能会引发NonUniqueEmailException,因此我们的Web API层可以将其转换为适当的问题详细信息。

@Consumes(MediaType.APPLICATION_JSON)
@Produces({ MediaType.APPLICATION_JSON, "application/problem+json" })
@POST
public Response register(@Valid final CreatePerson payload) {try {final Person person = service.register(payload.getEmail(), payload.getFirstName(), payload.getLastName());return Response.created(uriInfo.getRequestUriBuilder().path(person.getId()).build()).entity(person).build();} catch (final NonUniqueEmailException ex) {return Response.status(Response.Status.BAD_REQUEST).type("application/problem+json").entity(Problem.builder().withType(URI.create("http://localhost:21020/problems/non-unique-email")).withInstance(uriInfo.getRequestUri()).withStatus(Status.BAD_REQUEST).withTitle("The email address is not unique").withDetail(ex.getMessage()).with("email", payload.getEmail()).build()).build();}}

要触发此问题,只需运行服务器实例并尝试两次注册同一个人即可,就像我们在下面所做的那样。

$ curl -X POST "http://localhost:21020/api/people" \ -H  "Accept: */*" -H "Content-Type: application/json" \-d '{"email":"john@smith.com", "firstName":"John", "lastName": "Smith"}'HTTP/1.1 400                                                                              
Content-Type: application/problem+json                                                           {                                                                                         "type" : "http://localhost:21020/problems/non-unique-email",                            "title" : "The email address is not unique",                                            "status" : 400,                                                                         "detail" : "The email 'john@smith.com' is not unique and is already registered",        "instance" : "http://localhost:21020/api/people",                                       "email" : "john@smith.com"                                                              
}

太好了,因此我们的最后一个示例有些复杂,但同时可能是最现实的示例。 我们的Web API在很大程度上依赖Bean验证 ,以确保API使用者提供的输入有效。 我们如何将验证错误表示为问题的详细信息? 最直接的方法是提供专用的ExceptionMapper提供程序,它是JAX-RS规范的一部分。 让我们介绍一个。

@Provider
public class ValidationExceptionMapper implements ExceptionMapper<ValidationException> {@Context private UriInfo uriInfo;@Overridepublic Response toResponse(final ValidationException ex) {if (ex instanceof ConstraintViolationException) {final ConstraintViolationException constraint = (ConstraintViolationException) ex;final ThrowableProblem problem = Problem.builder().withType(URI.create("http://localhost:21020/problems/invalid-parameters")).withTitle("One or more request parameters are not valid").withStatus(Status.BAD_REQUEST).withInstance(uriInfo.getRequestUri()).with("invalid-parameters", constraint.getConstraintViolations().stream().map(this::buildViolation).collect(Collectors.toList())).build();return Response.status(Response.Status.BAD_REQUEST).type("application/problem+json").entity(problem).build();}return Response.status(Response.Status.INTERNAL_SERVER_ERROR).type("application/problem+json").entity(Problem.builder().withTitle("The server is not able to process the request").withType(URI.create("http://localhost:21020/problems/server-error")).withInstance(uriInfo.getRequestUri()).withStatus(Status.INTERNAL_SERVER_ERROR).withDetail(ex.getMessage()).build()).build();}protected Map<?, ?> buildViolation(ConstraintViolation<?> violation) {return Map.of("bean", violation.getRootBeanClass().getName(),"property", violation.getPropertyPath().toString(),"reason", violation.getMessage(),"value", Objects.requireNonNullElse(violation.getInvalidValue(), "null"));}
}

上面的代码片段区分了两种问题: ConstraintViolationException指示无效输入并映射到400 Bad Request ,而泛型ValidationException指示服务器端问题并映射到500 Internal Server Error 。 我们仅提取有关违规的基本详细信息,但是即使这样做,也可以大大改进错误报告功能。

$ curl -X POST "http://localhost:21020/api/people" \-H  "Accept: */*" -H "Content-Type: application/json" \-d '{"email":"john.smith", "firstName":"John"}' -i    HTTP/1.1 400                                                                    
Content-Type: application/problem+json                                              {                                                                               "type" : "http://localhost:21020/problems/invalid-parameters",                "title" : "One or more request parameters are not valid",                     "status" : 400,                                                               "instance" : "http://localhost:21020/api/people",                             "invalid-parameters" : [ {"reason" : "must not be blank",                                             "value" : "null",                                                           "bean" : "com.example.problem.resource.PeopleResource",                     "property" : "register.payload.lastName"                                    }, {                                                                          "reason" : "must be a well-formed email address",                           "value" : "john.smith",                                                     "bean" : "com.example.problem.resource.PeopleResource",                     "property" : "register.payload.email"                                       } ]                                                                           
}

这次捆绑到invalid-parameters成员中的附加信息非常冗长:我们分别知道类( PeopleResource ),方法( register ),方法的参数( 有效负载 )和属性( lastNameemail )(所有这些都从属性路径)。

有意义的错误报告是现代RESTful Web API的基础之一。 通常这并不容易,但绝对值得付出努力。 消费者(通常只是其他开发人员)应该对哪里出了问题以及如何处理有一个清晰的了解。 RFC 7807:HTTP API的问题详细信息是朝正确方向迈出的一步, 问题和问题弹簧网络之类的库在这里为您提供支持,请充分利用它们。

完整的源代码可在Github上找到 。

翻译自: https://www.javacodegeeks.com/2019/05/http-status-code-enough-tackling-web-apis-error-reporting.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/342496.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[渝粤教育] 华中科技大学 模拟电子技术基础 参考 资料

教育 -模拟电子技术基础-章节资料考试资料-华中科技大学【】 绪论测验题 1、【单选题】当输入信号频率为fL或fH时&#xff0c;放大电路电压增益的幅值约下降为通带内水平增益的 。 A、0.5倍 B、0.7倍 C、0.9倍 D、1倍 参考资料【 】 2、【单选题】某放大电路在负载开路时的输出…

远程抄表系统(AMR/AMI)中无线模块选型指南

1.概述 远程抄表系统是为提高水表、电表等能耗参数的综合计费管理水平而设计的新兴技术。它以全自动的抄表方式取代了传统的人工抄表方式&#xff0c;和同类抄表系统相比&#xff0c;具有网络结构自适应、免调试、免维护、运行稳定、方便扩展的特点。该系统采用先进的无线网络…

PoE供电六大常见问题大全解析

近年来&#xff0c;随着PoE供电技术的发展&#xff0c;从百兆到千兆&#xff0c;再到全千兆&#xff0c;PoE供电技术的发展势头越来越强劲。凭借简化用电设备的安装和部署、节能&#xff0c;安全等一系列优势&#xff0c;PoE供电成为无线覆盖、安防监控、以及智能电网等场景的新…

无线数传电台工业控制的应用

无线数传电台简单的说就是无线数传模块与多种工业通信接口的组合&#xff0c;无线数传电台具有工作温度范围广&#xff0c;电磁性能优良&#xff0c;抗干扰能力强&#xff0c;安装方便等优点。下面给大家介绍两款DTU&#xff0c;成都亿佰特有限公司的“E800-DTU”、“E810-DTU”…

433M无线串口E30-TTL-100在农业物联网上的应用

一、无线串口模块在农业物联网上的应用背景 智能农业&#xff0c;是通信、计算机和农学等若干学科和领域共同发展&#xff0c;并相互结合所形成的产物&#xff0c;它将信息采集、传输、处理和控制集成在一起&#xff0c;使人们更容易获得农作物生长各个阶段的各类信息&#xf…

普通交换机能否改成PoE供电的?

交换机相信大家都比较熟悉&#xff0c;一般说的交换机指的普通交换机&#xff0c;也就是最常见的那种。普通交换机可以传输交换数据&#xff0c;或者局域网内的多个电脑可以相互通信。PoE交换机指可以供电的交换机&#xff0c;跟普通交换机的区别是&#xff0c;它不仅而已传输交…

E70系列模块高效型、超低功耗无线cc1310芯片优势典型应用

E70系列是成都亿佰特电子科技有限公司基于TI公司CC1310射频芯片研发的无线串口模块&#xff08;UART&#xff09;&#xff0c;可工作在431~446.5MHz频段&#xff08;默认433MHz&#xff09;、861~876.5MHz频段&#xff08;默认868MHz&#xff09;、907~922.5MHz频段&#xff08…

飞畅科技-千兆/百兆/核心/PoE/光纤交换机选型指南

交换机是监控网络传输的核心设备。交换机的选型&#xff0c;有很多的重要技术参数需要考虑&#xff0c;硬件上包括百兆/千兆/万兆速率的端口、电口/光口/PoE口、端口数量、MAC地址表深度、转发延迟、缓存大小、VLAN、隔离等等。很多项目就是因为交换机选择当&#xff0c;出现各…

LoRa技术实现社区天然气抄表的应用

一、概述 以上图来自成都亿佰特科技有限公司自主研发的LoRa产品&#xff0c;分别是基于SX1278的433MHz频段的串口模块&#xff0c;基于SX1276的868MHz频段和915MHz频段的串口模块。该系列产品为小型贴片式&#xff0c;适用于可穿戴式&#xff0c;仪器仪表&#xff0c;手持式仪表…

LoRa技术在地质灾害预警上的应用

LoRa扩频技术具有超远距离通信&#xff0c;功率密度集中&#xff0c;抗干扰能力强的优势。成都亿佰特电子科技有限公司推出了几款适用于监测应用的DTU如 E90-DTU系列&#xff0c;E800-DTU系列&#xff0c;E32-DTU系列等。该系列相比同类进口的数传电台&#xff0c;具有功能先进…

[渝粤教育] 哈尔滨工业大学 大学计算机—计算思维导论 参考 资料

教育 -大学计算机—计算思维导论-章节资料考试资料-哈尔滨工业大学【】 第1讲之模拟练习题 1、【单选题】计算之树中&#xff0c;通用计算环境的演化思维是怎样概括的&#xff1f;。 A、程序执行环境—由CPU-内存环境&#xff0c;到CPU-存储体系环境&#xff0c;到多CPU-多存储…

飞畅科技教你如何快速选择工业网管poe交换机?

不管你是工程商还是渠道商&#xff0c;面对市面上品牌繁多&#xff0c;类型复杂&#xff0c;质量和价格也参差不齐的工业级网管交换机您是如何选择的&#xff1f;是否需要电源冗余、网络冗余&#xff0c;以及多样化的网管功能、平台化集中管理、防护、防雷等级又是多少、故障了…

亿佰特串口服务器接入阿里云物模型使用教程

在之前的文章中我们了解到虚拟串口软件作为TCP客户端来结合串口服务器使用&#xff0c;这一期我们来看一下串口服务器怎样接入阿里云物模型。 步骤详尽&#xff0c;一文读懂。 硬件准备 ME31-AXAX4040网络IO联网模块一台&#xff1b; MCGS的TPC7062组态屏一台&#xff1b; …

spring 异常捕获异常_跟踪异常–第5部分–使用Spring进行计划

spring 异常捕获异常看来我终于快要结束本系列有关使用Spring进行错误跟踪的博客了&#xff0c;对于那些还没有阅读该系列博客的人&#xff0c;我正在编写一个简单但几乎具有工业实力的Spring应用程序&#xff0c;扫描日志文件中的异常&#xff0c;然后生成报告。 在本系列的第…

亿佰特串口服务器接入阿里云MQTT协议的软件配置教程

在之前的文章中我们了解到虚拟串口软件作为TCP客户端来结合串口服务器使用&#xff0c;这一期我们来看一下串口服务器怎样接入阿里云物模型。 步骤详尽&#xff0c;一文读懂。 1.阿里云MQTT环境配置 ③点击“创建产品”&#xff0c;配置产品名称&#xff0c;选择“自定义品类…

三种安防监控摄像机供电方式,如何合理选择?

目前&#xff0c;监控摄像机的供电方式主要有以下三种&#xff1a;独立供电模式、集中供电模式、POE供电模式&#xff0c;其中POE供电模式又分为四种情况。那么&#xff0c;你对安防监控摄像机的这三种供电方式是否有所了解呢&#xff1f;接下来就由飞畅科技的小编来为大家详细…

串口服务器NB114产品MQTT协议软件配置教程

串口服务器&#xff08;NB114&#xff09;配置 串口服务器连接MQTT服务器方法参考“串口服务器用户手册”&#xff0c;不再重复说明。 3.设备驱动添加与处理 本次例程需要使用到TPC的两路串口以及两种收发协议&#xff0c;详细说明如下&#xff1a; ①在MCGS官网下载“MCGS_…

使用Spring Boot和Kubernetes构建微服务架构

“我喜欢编写身份验证和授权代码。” 〜从来没有Java开发人员。 厌倦了一次又一次地建立相同的登录屏幕&#xff1f; 尝试使用Okta API进行托管身份验证&#xff0c;授权和多因素身份验证。 在本教程中&#xff0c;您将使用Kubernetes将Spring Boot微服务架构部署到Google Clo…

物联网串口服务器的功能和作用

一、串口服务器是什么&#xff1f; 串口服务器提供串口转网络功能&#xff0c;能够将RS-232/485/422串口转换成TCP/IP网络接口,实现RS-232/485/422串口与TCP/IP网络接口的数据双向透明传输。使得串口设备能够立即具备TCP/IP网络接口功能,连接网络进行数据通信,极大的扩展串口设…

[渝粤教育] 三峡大学 电力电子技术(Ⅱ) 参考 资料

教育 -电力电子技术&#xff08;Ⅱ&#xff09;-章节资料考试资料-三峡大学【】 第一章 单元测试 1、【单选题】整流是以下哪两种电能形式之间的转换&#xff1f; A、AC-AC B、AC-DC C、DC-AC D、DC-DC 参考资料【 】 2、【单选题】充电宝在给手机锂电池充电的时候采用了以下哪…