提问人:Crystal2033 提问时间:10/24/2023 最后编辑:not_a_nerdCrystal2033 更新时间:10/25/2023 访问量:68
带有 @ExceptionHandler 的 GlobalExceptionHandler 或 ResponseEntity 用于来自服务器的 REST 应答?
GlobalExceptionHandler with @ExceptionHandler or ResponseEntity for REST answer from the server?
问:
我发现了两种返回错误状态代码的方法:第一种是传统的使用。第二种是为状态代码创建特定的异常,并使用 with 抛出这些异常作为服务器的应答。春天会抓住它并发送作为答案。RESTful API
ResponseEntity<>
GlobalExceptionHandler
@ExceptionHandler
@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);
}
}
我不知道什么更好。对于第二种方法,如下所示:Controller
@GetMapping("/products")
public Product getProduct(Long id){
return productsService.findById(id);
}
并作为:service
public Product findById(Long id) {
return productsRepository.findById(id).orElseThrow(
() -> new ResourceNotFoundException("Product with id " + id + " not found"));
}
最好的方法是什么,为什么?
如果第一种方法更好,是否很难获得 android 改造 api?如果服务器发送到我这边,我会得到什么?响应类?服务器 , 客户端 - 在 Android 上
ResponseEntity
Kotlin
Kotlin
ResponseEntity
Java Spring
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);
}
}
那么真相在哪里呢?
答:
最好让 Spring 进行异常处理。仅仅通过展示这 2 种方法,你就可以看到你将编写更少的代码,并且你的“业务”代码将更加干净,而没有这些 try 捕获。(当然,如果您出于某种原因想在某些地方使用这种方法,您可以自由选择)。
使用第一种方法,您可以轻松地使 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 );
}
因此,继承自的每个异常都将在此处处理(因此每次都以 404 REST 响应结束)。并会导致一些通用的错误对象,例如NotFoundExceptionParent
{
error: {
messageIdentifier: "some.message.identifier"
messageContent: "Item with id 5 was not found"
incidentUUID: "some-uuid"
// possibly more data
}
}
一般来说,您的消费者也可以处理。例如,如果我们能以一些简单的 FE 应用程序(Vue、Angular、React 等)为例,你可以很容易地实现一些默认处理(当然,你可以在某些地方覆盖),在非 2XX 响应时,在一些通用的错误 toast 中,只是打印(瞧,你有“几乎”免费:)的基本错误处理)error.messageContent
请记住,您也应该在那里进行一些“回退”错误处理,例如捕获 RuntimeException(如果可能),它将以大约 500 或其他方式结束。 另外,不要忘记添加一些额外的日志记录,全局异常处理程序是记录错误并可能为它们生成一些唯一标识符的理想场所,以便您可以在日志中轻松跟踪这些错误。
如果要对某些验证执行完全不同的处理(并且不想将其混合在一起),可以通过实现另一个具有不同异常父级的异常处理程序来实现。
要执行此错误处理,您唯一需要做的就是从任何地方抛出一些自定义异常。这听起来比应用程序蜂拥而至的尝试要好得多,不是吗。
最后说明:以“第一种方式”处理错误并不一定是坏方法,如果您的用例并不适合某些通用的异常处理系统,请随意使用自定义处理。但是,如果 Spring 可以为你做任何事情,为什么不让它:)
评论
s okay, we need to know what happened, but what about success status? We can not handle it with @ExceptionHandler. Or usually we do not need it? I
评论