接口设计需考虑到:
- 命名
- 参数列表
- 包装结构体
- 接口粒度
- 版本策略
- 幂等性实
- 同步/异步处理
微服务架构下,如果接口设计思路和调用方理解不一致,就会导致很多问题。
接口的响应要明确接口的处理结果
某下单接口响应体包含
- success
- code
- info
- message
- 二级嵌套对象data结构体
有时下单操作的响应结果是:
success=true、message=OK,貌似代表下单成功
但info却提示订单存在风险,code是个1001错误码,data中能看到订单状态是Cancelled,订单ID是-1,好像又表示下单失败。
有时下单接口又返回:
success=false,message=非法用户ID,似乎表示下单失败
但data里的orderStatus是Created、info是空、code是0。
下单到底是成功还是失败呢?
于是,我们开始好奇了
- 结构体的code和HTTP响应状态码,是什么关系
- success到底代表下单成功还是失败
- info和message的区别是什么
- data中永远都有数据吗?什么时候应该去查询data?
混乱原因是该下单服务本身并非真正执行下单,只是做一些预校验和预处理,真正的下单操作,需要下单服务内部调用另一个订单服务来处理;订单服务处理完成后,会返回订单状态和ID。
一切正常时,下单后的订单状态就是Created,订单ID是一个大于0数字。而结构体中的message和success,其实是下单服务的处理异常信息和处理成功与否的结果,code、info是调用订单服务的结果。
- 刚才的第一个调用,下单服务自己没问题,success是true,message是OK,但调用订单服务时却因为订单风险问题被拒绝,所以code是5001,info是Risk order detected,data中的信息是订单服务返回的,所以最终订单状态是Cancelled
- 第二个调用,因为用户ID非法,所以下单服务在校验了参数后直接就返回了success是false,message是Illegal userId。因为请求未到订单服务,所以info、code、data都是默认值,而订单状态的默认值又是Created。因此,第二次下单肯定失败了,但订单状态却是Created。
可见混乱的接口定义和实现方式,无法让调用者分清到底该怎么处理。为将接口设计更合理,需考虑:
- 对外隐藏内部实现
虽然下单服务调用订单服务进行真正的下单操作,但是直接接口其实是下单服务提供的,下单服务不该“直接”暴露其背后订单服务的状态码、错误描述 - 设计接口结构时,明确每个字段的含义,以及客户端的处理方式。
遵循以上规则,现在调整返回结构体,去掉外层的info,即不再把订单服务的调用结果告知客户端:
@Data public class APIResponse<T> { private boolean success; private T data; private int code; private String message; }
明确接口设计:
- 若出现非200状态码,即代表请求没有到下单服务,可能网络超时。这时,肯定无法拿到服务端的响应体,客户端可以给予友好提示,比如让用户重试,不需要继续解析响应结构体
- 若响应码是200,解析响应体查看success,为false代表下单请求处理失败,可能是因为收单服务参数验证错误,也可能因为订单服务下单操作失败。再根据下单服务定义的错误码表和code,做相应处理。比如友好提示,或是让用户重新填写相关信息,其中友好提示的文字内容可从message获取
- success为true时,才需继续解析响应体中的data结构体,其代表业务数据,通常有如下情况:
- 通常情况下,success为true时订单状态是Created,获取orderId属性可以拿到订单号。特殊情况下,比如收单服务内部处理不当,或是订单服务出现了额外的状态,虽然success为true,但订单实际状态不是Created,这时可以给予友好的错误提示。