采用http协议进行数据交互
在spring cloud微服务交互中,基本上还是采用http协议进行数据交互。
与dubbo不同的是,http协议与编程语言无关,所以无法向dubbo一样,将抛出的Exception的内容进行序列化传到调用方,所以只能采用错误码的方式来传递异常消息。
数据的包装形式
统一数据格式
正常数据
{
"code": 2000,
"message": "bad server",
"data":{...}
}
错误数据
{
"code": 5000,
"message": "bad server" }
区分数据与错误码
当调用正常的情况下,只需要返回完整的数据对象即可。
josnObject or jsonArray
当出现错误的情况下,只需要返回错误码即可。
在提供方接受到错误码后,可以再转化为java中的异常抛出
{
"code": 5000,
"message": "bad server" }
总结
正常数据和错误码如果统一用一个包装类进行包装,会带来一些弊端
- 在取数据的时候还要进行同一的getData()操作,十分不便。
- 返回结果没有Exception的概念。使用try…catch的方式处理业务,可以让业务代码更集中,异常可以统一处理,避免了在业务代码中各种if…else语句乱飞,异常处理不能统一,不好组织代码。
业务场景分析
微服务间的数据调用一般可以分为
- 获取数据
- 验证数据
- 提交数据
数据查询
对于简单的查询,只关心查询结果数据,没必要再外包装一层getData()。
验证数据
比如authServer,在各个网关模块中都会引用authClient对前端提交过来的token进行校验。
在校验过程中可能会返回多种校验结果,校验成功并返回身份信息,token过期,token无效等。
token过期,token无效对于网关模块中并不需要进行处理,只要直接往上抛即可。
这种场景下,使用异常的异常的是比较适合的。
提交数据
在提交数据的时候,接口实现方为了流程的完整,对接受的参数进行校验,这种情况下,如果校验不通过,返回错误码。
使用try…catch很方便对业务进行统一判断,或者当前服务不知道如何处理这些异常,直接向上层服务抛出,如果使用if…else处理这些问题是有点力不从心。
try {
a.postData(obj);
a.postData(obj);
a.postData(obj);
} catch(Exception e) {
// doSomething or throw e
}
异常码是否应该统一问题
返回的业务异常码都应该有唯一的一个含义,对于上层的调用方,才能确定到底出了什么问题并决定是继续向上抛出或者处理它。
对于最外层的网关服务,给其他外部服务调用,基于以下需求,需要自定义一套异常码(外码)
当下游服务抛出很精确的异常码(内码),对于外部服务来讲,它是不关心的,或者基于之前和外部调用方定义的接口返回规范,我们必须异常信息转换。
例如,当insert数据失败抛出数据库错误,下游服务层层抛出,在网关中得到异常信息为
{
"code": 7894,
"message": "insert mysql error" }
对外,我们并不需要提供这么明确的信息,或者这个内部使用的异常码并未在接口调用规范中声明,我们希望返回给调用者的信息为
{
"code": 5000,
"message": "bad server" }
结论
异常码应该统一内码,外码可以与外部调用者进行协商定义自己的一套。
对于内部异常码和外部异常码的对应关系,在网关服务中声明好对应关系