1. 接口参数校验
入参出参校验是每个程序员必备的基本素养。你设计的接口,必须先校验参数。比如入参是否允许为空,入参长度是否符合你的预期长度。这个要养成习惯哈,日常开发中,很多低级bug都是不校验参数导致的。
比如你的数据库表字段设置为 varchar(16) ,对方传了一个32位的字符串过来,如果你不校验参数, 插入数据库直接异常了 。
出参也是,比如你定义的接口报文,参数是不为空的,但是你的接口返回参数,没有做校验,因为程序某些原因,直返回别人一个 null 值。。。

2. 修改老接口时,注意接口的兼容性
很多bug都是因为修改了对外旧接口,但是却 不做兼容 导致的。关键这个问题多数是比较严重的,可能直接导致系统发版失败的。新手程序员很容易犯这个错误哦~

所以,如果你的需求是在原来接口上修改,尤其这个接口是对外提供服务的话,一定要考虑接口兼容。举个例子吧,比如dubbo接口,原本是只接收A,B参数,现在你加了一个参数C,就可以考虑这样处理:
//老接口
void oldService(A,B){
//兼容新接口,传个null代替C
newService(A,B,null);
}
//新接口,暂时不能删掉老接口,需要做兼容。
void newService(A,B,C){
...
}
3. 设计接口时,充分考虑接口的可扩展性
要根据实际业务场景设计接口,充分考虑接口的可扩展性。
比如你接到一个需求:是用户添加或者修改员工时,需要刷脸。那你是反手提供一个员工管理的提交刷脸信息接口?还是先思考:提交刷脸是不是通用流程呢?比如转账或者一键贴现需要接入刷脸的话,你是否需要重新实现一个接口呢?还是当前按业务类型划分模块,复用这个接口就好,保留接口的可扩展性。
如果按模块划分的话,未来如果其他场景比如一键贴现接入刷脸的话,不用再搞一套新的接口,只需要新增枚举,然后复用刷脸通过流程接口,实现一键贴现刷脸的差异化即可。

4.接口考虑是否需要防重处理
如果前端重复请求,你的逻辑如何处理?是不是考虑接口去重处理。
当然,如果是查询类的请求,其实不用防重。如果是更新修改类的话,尤其金融转账类的,就要过滤重复请求了。简单点,你可以使用Redis防重复请求,同样的请求方,一定时间间隔内的相同请求,考虑是否过滤。当然,转账类接口,并发不高的话, 推荐使用数据库防重表 ,以 唯一流水号作为主键或者唯一索引 。

5. 重点接口,考虑线程池隔离。
一些登陆、转账交易、下单等重要接口,考虑线程池隔离哈。如果你所有业务都共用一个线程池,有些业务出bug导致线程池阻塞打满的话,那就杯具了, 所有业务都影响了 。因此进行线程池隔离,重要业务分配多一点的核心线程,就更好保护重要业务。

6. 调用第三方接口要考虑异常和超时处理
如果你调用第三方接口,或者分布式远程服务的的话,需要考虑:
-
异常处理
比如,你调别人的接口,如果异常了,怎么处理,是重试还是当做失败还是告警处理。
-
接口超时
没法预估对方接口一般多久返回,一般设置个超时断开时间,以保护你的接口。 之前见过一个生产问题 ,就是http调用不设置超时时间,最后响应方进程假死,请求一直占着线程不释放,拖垮线程池。
-
重试次数
你的接口调失败,需不需要重试?重试几次?需要站在业务上角度思考这个问题
7. 接口实现考虑熔断和降级
当前互联网系统一般都是分布式部署的。而分布式系统中经常会出现某个基础服务不可用,最终导致整个系统不可用的情况, 这种现象被称为 服务雪崩效应 。
比如分布式调用链路 A->B->C.... ,下图所示:

如果服务C出现问题,比如是 因为慢SQL导致调用缓慢 ,那将导致B也会延迟,从而A也会延迟。堵住的A请求会消耗占用系统的线程、IO等资源。当请求A的服务越来越多,占用计算机的资源也越来越多,最终会导致系统瓶颈出现,造成其他的请求同样不可用,最后导致业务系统崩溃。
为了应对服务雪崩, 常见的做法是 熔断和降级 。最简单是加开关控制,当下游系统出问题时,开关降级,不再调用下游系统。还可以选用开源组件 Hystrix 。
8. 日志打印好,接口的关键代码,要有日志保驾护航。
关键业务代码无论身处何地,都应该有足够的日志保驾护航。比如:你实现转账业务,转个几百万,然后转失败了,接着客户投诉,然后你还没有打印到日志,想想那种水深火热的困境下,你却毫无办法。。。
那么,你的转账业务都需要哪些日志信息呢?至少,方法调用前,入参需要打印需要吧,接口调用后,需要捕获一下异常吧,同时打印异常相关日志吧,如下:
public void transfer(TransferDTO transferDTO){
log.info("invoke tranfer begin");
//打印入参
log.info("invoke tranfer,paramters:{}",transferDTO);
try {
res= transferService.transfer(transferDTO);
}catch(Exception e){
log.error("transfer fail,account:{}",
transferDTO.getAccount())
log.error("transfer fail,exception:{}",e);
}
log.info("invoke tranfer end");
}
之前写过一篇打印日志的15个建议,大家可以看看哈:

本文详细列举了接口设计中需要注意的36个关键技巧,包括接口参数校验、兼容性、可扩展性、防重处理、线程池隔离、异常处理、熔断降级、日志记录、功能定义、异步处理、接口耗时优化、批量处理、缓存利用、热点数据隔离、配置化参数、幂等性设计、读写分离、返回数据量控制、SQL优化、代码锁粒度、接口状态与错误处理、异常处理建议、程序逻辑优化、大文件事务对象处理、限流策略、运行时异常避免、接口安全性、分布式事务、事务失效场景、设计模式应用、线性安全问题、接口定义规范、版本控制、代码规范及沟通协作等方面,旨在提升接口设计的质量和稳定性。
最低0.47元/天 解锁文章
2万+

被折叠的 条评论
为什么被折叠?



