一、简介
阿波罗手机端是所有销售和销售主管(5000多人)使用的销售终端。销售可以使用阿波罗手机随时随地接收通知、查看业绩、录入拜访、维护客户、方案等信息,大大提高销售的工作效率(日活4000多人)。同时,阿波罗手机端还在公司内率先采用混合模式开发app,在提高开发效率的同时也为其他手机团队积累了框架和经验。
目前阿波罗各个服务提供方都提供了Restful服务供手机端调用。由于Restful服务是通过HTTP形式供手机端来消费的,所以我们设计了一套简单的状态码扩展来实现前后端对异常的统一处理。
下文就会对这一机制做一个详细的介绍。
二、概览
阿波罗的后端服务和手机app交互的接口是通过HTTP接口返回JSON格式来达成的。
为了使接口在提供正常服务的同时兼顾异常处理,我们约定了使用HTTP状态码和JSON对象状态码来定义服务状态。
2.1 HTTP状态码
作为基于HTTP的服务,HTTP自身的状态码是我们首要可以利用的资源。
目前我们主要使用HTTP状态码来标识具体业务以外的状态,如:
请求示例:
响应示例:
2.2 JSON对象状态码
由于后台系统的复杂性,每个业务除了实际的对象数据之外,还需要返回提示信息给用户,如操作失败,数据验证失败等。
为了使后端服务接口统一化,我们设计了以下的数据格式来满足业务场景的需求。需要注意的是,对以下情况,HTTP状态码都是200。
三、具体实现
3.1 服务端
3.1.1 HTTP状态码
对于HTTP状态码,我们应用所需要处理的只有401。
其它两个状态码(200,500)都是服务器(nginx和tomcat)默认的行为。
如手机App的统一认证机制所述,
后端服务是通过filter来统一对请求做安全认证的。所以如果发现请求身份验证没通过,只需要在filter中直接设置响应状态为Unauthorized即可。
3.1.2 JSON对象状态码
相对HTTP状态码而言,JSON对象状态码和业务的耦合程度更高,场景也更复杂。
所以我们需要的是一种尽量对实际业务无侵入、代码开发量最小的实现方式。
在综合了各种方案和实现复杂度后,我们选定了通过Spring MVC的ControllerAdvice和ExceptionHandler来实现。
大致过程是:
- 我们在应用中通过ControllerAdvice注册一个全局的Exception handler来捕获所有的应用异常
- 在Exception handler中,对捕获到的异常进行处理,把异常转换成如2.2节中所约定的格式
- 为了能使Exception handler区分出服务错误和校验错误,我们设计了一个
ValidationException
类来存储所有的校验异常
- 在业务代码中,只需要专注于自身的业务实现,对于自身或者第三方的服务异常,可以选择捕获后处理或者直接抛出
- 对于校验错误,只需要构建一个
ValidationException
对象,存入校验信息后抛出即可
以下是具体实现。
ControllerAdvice:
ValidationException
请求处理失败示例代码:
校验错误示例代码:
3.2 客户端
在客户端,为了统一处理服务端的状态码,我们首先对ajax进行了一个封装。
这个封装和普通的ajax方法不同之处只是在于对服务返回成功(HTTP状态码为200)的情况做了细化,区分出了JSON状态码不为200的情况,
然后调用error callback,并传入解析出的状态码和状态信息。对于正常返回的请求,则直接取出实际业务对象返回。
所以,服务端制定的code和msg这套格式对于实际的业务调用是透明的。
ajax封装示例:
业务调用示例:
四、小结
通过这样一套机制,我们解决了阿波罗App调用后端服务的统一异常处理问题,同时还收获了以下好处:
- 异常处理统一实现,维护性和扩展性较好
- 在后端统一由
ExceptionHandler
实现
- 在前端统一由自定义的ajax封装实现
- 后端实现对业务代码透明,保证了接口的统一行为