一、引子
大多数人写后端的api时,都喜欢这样定义响应:
HTTP 200 OK
...headers
{
code: 500,
msg: "error"
data: T
}
你是不是这样写的呢?反正我刚开始做项目的时候,是这样写的,现在很多的项目也大多是这样写的。
我查了查网上的资料,一种说法是一些地区的网络运营商会劫持4xx和5xx请求,所以一律把http的状态码改成200,所有异常的状态码放在响应体中,但是现在有了https,除非中间人有那个能力搞到你的证书(有那个能力就直接在你的服务器动手脚了,还劫持你请求干啥),不然从概率学上是不可能篡改你的请求的。而且就算是不用https,也可以用自定义请求头等更优雅的办法来解决这个问题。
二、回顾HTTP状态码
先来看看HTTP状态码:
标准的http状态码有五类,分别是:
1xx
: 通知2xx
: 成功3xx
: 重定向4xx
: 客户端错误5xx
: 服务端错误
可以看到这些分类是很明确的,对于客户端来讲,只需要在业务代码里处理2xx,4xx就可以了,因为1xx和3xx对开发者是透明的,http调用框架(ajax、retrofit、axios等等)会自动处理;5xx是后端的锅,服务器炸掉了,和客户端开发者就更没关系了。
三、如何设计
首先,在我们的后端代码中,要自定义一个业务异常,在抛出该异常之后,异常处理切面就将响应的状态码改成4xx,其余的异常类型,http状态码都设置成5xx。因为抛出ServiceException的肯定是我们验证客户端发送来的数据出了问题,比如参数错误、权限不足等,用户改改参数就可以解决这个异常。而其他异常,比如NPE,客户端怎么改参数都是没用的,因为是服务器的代码有问题。当然你也可以将诸如HibernateValidation2.0(JSR380)的ConstraintViolation异常的http状态码也设置成4xx,看你系统具体的设计了。
3.1 自定义业务异常
@Getter
@Setter
public class ServiceException extends RuntimeException{
// 该异常要返回什么样的http状态码,常用的有:
// 400 BAD_REQUEST, 客户端的请求参数错误
// 403 FORBIDDEN, 服务器理解请求客户端的请求,但是拒绝执行此请求,例如考试系统,用户在考试开始前请求获取试卷
private HttpResponseCode httpCode;
//异常的编号,一般为模块编号+异常编号