web api开启错误提示_当HTTP状态代码不足时:处理Web API错误报告
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。 為了簡單起見,僅公開了兩個端點:注冊和按人員標識符查找。
撇開開發現實世界服務時可能遇到的大量問題和業務約束,即使使用此簡單的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異常非常相似,并且確實是一個,因為AbstractThrowableProblem是RuntimeException的子類。 因此,我們可以從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" }請注意,響應中包含了application / problem + 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 ),方法的參數( 有效負載 )和屬性( lastName和email )(所有這些都從屬性路徑)。
有意義的錯誤報告是現代RESTful Web API的基礎之一。 通常這并不容易,但絕對值得付出努力。 消費者(通常只是其他開發人員)應該對哪里出了問題以及如何處理有一個清晰的了解。 RFC 7807:HTTP API的問題詳細信息是朝正確方向邁出的一步, 問題和問題彈簧網絡之類的庫在這里為您提供支持,請充分利用它們。
完整的源代碼可在Github上找到 。
翻譯自: https://www.javacodegeeks.com/2019/05/http-status-code-enough-tackling-web-apis-error-reporting.html
web api開啟錯誤提示
總結
以上是生活随笔為你收集整理的web api开启错误提示_当HTTP状态代码不足时:处理Web API错误报告的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 靖江备案价(南靖备案价)
- 下一篇: 网络犯罪案例分析题及答案(网络犯罪案例d