带有 @ExceptionHandler 的 GlobalExceptionHandler 或来自服务器的 REST 响应的 ResponseEntity?

问题描述 投票:0回答:1

我发现了两种从 RESTful API 返回错误状态代码的方法:第一种是传统的使用 ResponseEntity<>。第二种是为状态代码创建特定的异常,并使用 GlobalExceptionHandler 和 @ExceptionHandler 抛出这些异常作为服务器的答案。 Spring 将捕获它并作为答案发送。

@ControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
    @ExceptionHandler
    public ResponseEntity<AppError> catchResourceNotFoundException(ResourceNotFoundException e) {
        log.error(e.getMessage(), e);
        return new ResponseEntity<>(new AppError(HttpStatus.NOT_FOUND.value(), e.getMessage()), HttpStatus.NOT_FOUND);
    }
 }

我不知道什么更好。对于第二种方法,控制器将如下所示:

@GetMapping("/products")
    public Product getProduct(Long id){
            return productsService.findById(id);
    }

服务为:

public Product findById(Long id) {
        return productsRepository.findById(id).orElseThrow(
                () -> new ResourceNotFoundException("Product with id " + id + " not found"));
    }
  1. 最好的方法是什么?为什么?

  2. 如果第一种方法更好,在 kotlin android Retrofit api 上获取 ResponseEntity 是否很难?如果服务器发送到我的 kotlin 端 ResponseEntity,我会得到什么?响应类?服务器在 Java Spring 上,客户端在 Android kotlin 上

有人说 ResponseEntity 是从服务器发送数据的最佳方法。有人说使用 ResponseEntity 的返回值读取控制器很困难,如下所示:

@GetMapping("/products")
    public ResponseEntity<?> getProduct(Long id){
        try {
            Product product = productsService.findById(id).orElseThrow();
            return new ResponseEntity<>(product, HttpStatus.OK);
        } catch (Exception e){
            return new ResponseEntity<>(new AppError(HttpStatus.NOT_FOUND.value(), 
                    "Product with id " + id + " nor found"),
                    HttpStatus.NOT_FOUND);
        }
    }

那么真相在哪里?

java rest kotlin retrofit2 response-entity
1个回答
0
投票

让 Spring 进行异常处理总是更好。只需展示这两种方法,您就可以看到,如果没有这些 try catch,您将编写更少的代码,并且您的“业务”代码将更加干净。 (当然,如果你出于某种原因想在某些地方使用这种方法,你可以随意)。

使用第一种方法,您可以轻松地使您的 REST API 对于使用它的用户来说更加方便和可读。

例如,您可以创建一个全局异常处理程序和一组异常子项,您可以轻松地将它们映射到正确的错误代码和可能的错误消息。

@ResponseStatus(NOT_FOUND)
@ExceptionHandler(NotFoundExceptionParent.class)
@ResponseBody
public ResponseEntity<GenericErrorObject> notFoundExceptionHandling(NotFoundExceptionParentex) {
    // Get message locale.id from given exception in language that user uses (you can store arguments in exception so you can easily fill arguments to that message, for example saying "Entity with id {} was not found"
    // Create generic object that holds that error message
    GenericErrorObject genericError = createGenericObject(ex);

    return ResponseEntity.status(NOT_FOUND_STATUS).body(genericError );
}

因此,从

NotFoundExceptionParent
继承的每个异常都将在这里处理(因此每次都会以 404 REST 响应结束)。并会导致一些通用错误对象,例如

{
 error: {
   messageIdentifier: "some.message.identifier"
   messageContent: "Item with id 5 was not found"
   incidentUUID: "some-uuid"
   // possibly more data
 }
}

您的消费者一般也可以处理。例如,如果我们可以使用一些简单的 FE 应用程序(Vue、Angular、React 等),您可以轻松实现一些默认处理(当然您可以在某些地方覆盖),在非 2XX 响应时,这些默认处理将在某些情况下实现通用错误吐司,其中只是打印

error.messageContent
(瞧,您已经“几乎”免费了基本的错误处理:))

请记住,您也应该在那里进行一些“后备”错误处理,例如捕获以 500 或其他值结束的 RuntimeException(如果可能)。 另外,不要忘记添加一些额外的日志记录,全局异常处理程序是记录错误的完美位置,并可能为它们生成一些唯一的标识符,以便您可以在日志中轻松跟踪这些错误。

如果您想对某些验证执行完全不同的处理(并且您不想将其混合在一起),您可以通过实现另一个具有不同异常父级的异常处理程序来实现。

要执行此错误处理,您唯一要做的就是从任何地方抛出一些自定义异常。这听起来比应用程序蜂拥而至的 try catch 好得多,不是吗。

© www.soinside.com 2019 - 2024. All rights reserved.