企业网站模块介绍,长春火车站进站需要核酸检测吗,南京网站设计公司济南兴田德润简介图片,wordpress的function命名我们来谈谈痛点吧。由于我的职责#xff0c;我必须使用许多不同的服务#xff08;进行编辑、进行代码审查......#xff09;#xff1b;不同的团队通常会编写所有这些服务#xff0c;每当涉及到处理错误并从服务转发错误时#xff0c;有时我的眼睛就会开始流泪。让我尝试… 我们来谈谈痛点吧。由于我的职责我必须使用许多不同的服务进行编辑、进行代码审查......不同的团队通常会编写所有这些服务每当涉及到处理错误并从服务转发错误时有时我的眼睛就会开始流泪。让我尝试告诉您哪些代码在我看来是不可接受的错误处理以及我认为应该如何处理。 一般来说最初问题隐藏在服务分析的缺陷中。通常对于如何抛出错误没有参考要求。一般来说发生这种情况有两个原因第一个是急于开发新服务第二个是分析师信任开发人员的经验。在这种情况下分析师只需告诉开发人员“好吧稍后给我一个错误消息的示例我将在汇合中附加它。” 让我们继续看例子让我们看看这种方法在开发中的后果。
首先不要做的就是抛出 RuntimeException
public Object badExample() {throw new RuntimeException(Something wrong!);
}
展示 调用服务或客户端将收到 500 错误并且无法理解其请求出了什么问题。您认为在这种情况下需要多长时间才能发现问题它会随着你的代码量成比例增长。如果你有一个方法调用链那么在服务内部调用方法时处理此类消息就会变得更加困难。
如何改进呢首先让我们创建一个错误处理程序几乎所有框架都开箱即用在我的示例中我将使用 Spring 框架处理程序。
例子
ControllerAdvice
public class ApiExceptionHandler {ExceptionHandler(value {RuntimeException.class})public ResponseEntityObject handler(RuntimeException e) {HttpStatus badRequest HttpStatus.INTERNAL_SERVER_ERROR;return new ResponseEntity(e.getMessage(), badRequest);}...
展示 现在我们看到了消息但是消息的格式是字符串而不是 JSON。我们很快就会解决这个问题。 理想情况下项目中的所有服务都应具有相同的错误消息格式。至少有两个字段是消息本身和内部整数错误代码。我想没有必要说明为什么消息文本不足以及需要多少资源来处理该字符串。
例子
public class ExampleApiError {private String message;private Integer code;private LocalDateTime dateTime;... 我们将在错误处理程序中填充此类。但正如我所说抛出 RuntimeException 是一种不好的做法因此您需要创建自己的类来抛出错误在该类的构造函数中我们将传递一条消息和一个错误代码。
public class ApiException extends RuntimeException {private final int code;public ApiException(String msg, int code) {super(msg);this.code code;}...
似乎一切都更加清楚了但即使在这里问题也开始了每个人都以不同的方式创建传递给类构造函数的参数。有些直接在方法中创建消息和错误代码。
例子
public Object badExample() {throw new ApiException(Something wrong!, 10);
}
在代码中找到这样的地方仍然很困难。嗯首先想到的是创建常量类一个类用于消息第二个类用于消息代码。
例子
public static final String SOMETHING_WRONG Something wrong;
public static final int SOMETHING_WRONG_CODE 10;public Object badExample() {throw new ApiException(SOMETHING_WRONG, SOMETHING_WRONG_CODE);
} 当您知道错误代码在哪里时这已经更好、更具可读性并且更容易找到。 但是如果您没有微服务那么将所有内容存储在一个类中可能不是一个好主意。消息开始变得越来越大因此最好根据方法的功能来分离常量类这些常量类将与 ProductExceptionConstant、PaymentExceptionConstant 等一起使用。 但这还不是全部。对某些人来说这可能看起来很过时但常量需要创建为枚举或接口。接口中的变量默认是静态的、公共的和最终的。我并不反对这种做法最重要的是一切都应该是统一的如果您开始通过接口进行操作则继续这样做无需混合。在其中一个项目中我看到同一团队使用三种不同的常量方法。你不必这样做。 我将再展示一个在审核过程中引起我注意的真实项目的示例。 首先开发人员决定他返回的所有实体都将包含错误消息和错误代码并且状态将始终为 200在我看来这会误导调用者。嗯一个常量的例子。
public enum ErrorsEnum {DEFAULT_ERROR(ErrorsConstants.DEFAULT_ERROR, 400),REFRESH_TOKEN_NOT_VALID(ErrorsConstants.REFRESH_TOKEN_NOT_VALID, 400.1),USER_NOT_FOUND(ErrorsConstants.USER_NOT_FOUND, 400.2),
在我看来代码 9 3 \ 4 丢失了。默认情况下在这种情况下您可以使用数字 Pi。 如果您对我的方法感兴趣那就继续吧。最方便的事情是创建一个接口它将成为每个人都有约束力的契约。
public interface ExceptionBase {String getMsg();Integer getCode();
}
并且需要更改异常类的构造函数。
public ApiException(ExceptionBase e) {super(e.getMsg());this.code e.getCode();
}
现在每个尝试抛出异常的人都会明白我们必须将实现接口的对象传递给构造函数。最合适的选择是 Enum。
例子
/*** This class is intended for declaring exceptions that occur during order processing. code range* 101-199.*/
public enum OrderException implements ExceptionBase {ORDER_NOT_FOUND(Order not found., 101),ORDER_CANNOT_BE_UPDATED(Order cannot be updated,, 102);OrderException(String msg, Integer code) {this.msg msg;this.code code;}private final String msg;private final Integer code;Overridepublic String getMsg() {return msg;}Overridepublic Integer getCode() {return code;}
}
使用示例
public Object getProduct(String id) {if (id.equals(-1)) {throw new ApiException(OrderException.ORDER_NOT_FOUND);}
...
服务器响应 因此我们有以下异常包模型。 正如您所看到的没什么复杂的逻辑很容易阅读。在此示例中我在 ApiException 类中留下了一个接受字符串的构造函数但为了可靠性最好将其删除。
通常代码中的大多数不一致都是由于缺乏代码检查或检查不力造成的。最常见的借口是“这是一个临时解决方案我们稍后会修复它”但不它不会那样工作没有人会费心寻找哪里有临时解决方案哪里有永久解决方案。事实证明“暂时的就是永久的”。
如果您有很多相互通信的服务那么通过制作一种错误消息格式您将大大简化编写客户端库的工作。例如使用Retrofit时一旦编写了处理程序核心您只需更改接口中的方法和接收的对象即可。
结论
错误处理是代码中非常重要的部分它可以轻松地找到代码中的问题区域并且还允许外部客户端了解他们在使用端点时做错了什么因此您应该从编写项目的第一阶段就对此给予适当的关注。
示例代码在这里。
我希望读完这篇文章后你的生活会变得更轻松一些。一切成功。